To reduce shader state changes and compilations, just use the
four-bone-per-vertex configuration for all skinned meshes. Depending on the models we have, it may be worth compiling a separate one for two bones per vertex. Added a hook to customize the material color (for per-vertex colors, e.g.) git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@245 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -19,24 +19,14 @@
|
|||||||
// License along with this library; if not, write to the Free Software
|
// License along with this library; if not, write to the Free Software
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
#if BONES_PER_VERTEX == 4
|
|
||||||
#define ATTRIB_TYPE vec4
|
|
||||||
#elif BONES_PER_VERTEX == 3
|
|
||||||
#define ATTRIB_TYPE vec3
|
|
||||||
#elif BONES_PER_VERTEX == 2
|
|
||||||
#define ATTRIB_TYPE vec2
|
|
||||||
#else
|
|
||||||
#define ATTRIB_TYPE float
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** The bone transforms. */
|
/** The bone transforms. */
|
||||||
uniform mat4 boneTransforms[MAX_BONE_COUNT];
|
uniform mat4 boneTransforms[MAX_BONE_COUNT];
|
||||||
|
|
||||||
/** The bone indices. */
|
/** The bone indices. */
|
||||||
attribute ATTRIB_TYPE boneIndices;
|
attribute vec4 boneIndices;
|
||||||
|
|
||||||
/** The bone weights. */
|
/** The bone weights. */
|
||||||
attribute ATTRIB_TYPE boneWeights;
|
attribute vec4 boneWeights;
|
||||||
|
|
||||||
/** The amount of fog. */
|
/** The amount of fog. */
|
||||||
#ifdef FOG
|
#ifdef FOG
|
||||||
@@ -51,17 +41,13 @@ void main ()
|
|||||||
vec4 normal4 = vec4(gl_Normal, 0.0);
|
vec4 normal4 = vec4(gl_Normal, 0.0);
|
||||||
|
|
||||||
// add up the vertex as transformed by each bone and scaled by each weight
|
// add up the vertex as transformed by each bone and scaled by each weight
|
||||||
#if BONES_PER_VERTEX == 1
|
vec4 modelVertex = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
vec4 modelVertex = boneTransforms[int(boneIndices)] * gl_Vertex * boneWeights;
|
vec4 modelNormal = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
vec4 modelNormal = boneTransforms[int(boneIndices)] * normal4 * boneWeights;
|
for (int ii = 0; ii < 4; ii++) {
|
||||||
#else
|
mat4 boneTransform = boneTransforms[int(boneIndices[ii])];
|
||||||
vec4 modelVertex = boneTransforms[int(boneIndices[0])] * gl_Vertex * boneWeights[0];
|
modelVertex += boneTransform * gl_Vertex * boneWeights[ii];
|
||||||
vec4 modelNormal = boneTransforms[int(boneIndices[0])] * normal4 * boneWeights[0];
|
modelNormal += boneTransform * normal4 * boneWeights[ii];
|
||||||
for (int ii = 1; ii < BONES_PER_VERTEX; ii++) {
|
}
|
||||||
modelVertex += boneTransforms[int(boneIndices[ii])] * gl_Vertex * boneWeights[ii];
|
|
||||||
modelNormal += boneTransforms[int(boneIndices[ii])] * normal4 * boneWeights[ii];
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// apply the standard transformation
|
// apply the standard transformation
|
||||||
gl_Position = gl_ModelViewProjectionMatrix * modelVertex;
|
gl_Position = gl_ModelViewProjectionMatrix * modelVertex;
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ public class SkinMesh extends ModelMesh
|
|||||||
if (bonesPerVertex > MAX_SHADER_BONES_PER_VERTEX) {
|
if (bonesPerVertex > MAX_SHADER_BONES_PER_VERTEX) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_sconfig = new SkinShaderConfig(scache, bonesPerVertex, _emissiveMap != null);
|
_sconfig = new SkinShaderConfig(scache, _emissiveMap != null);
|
||||||
if (_sconfig.update(getBatch(0).states)) {
|
if (_sconfig.update(getBatch(0).states)) {
|
||||||
setShaderAttributes();
|
setShaderAttributes();
|
||||||
setRenderState(_sconfig.getState());
|
setRenderState(_sconfig.getState());
|
||||||
@@ -618,20 +618,19 @@ public class SkinMesh extends ModelMesh
|
|||||||
*/
|
*/
|
||||||
protected void setShaderAttributes ()
|
protected void setShaderAttributes ()
|
||||||
{
|
{
|
||||||
int bonesPerVertex = _sconfig.getBonesPerVertex();
|
int size = getBatch(0).getVertexCount() * 4;
|
||||||
int size = getBatch(0).getVertexCount() * bonesPerVertex;
|
|
||||||
ByteBuffer bibuf = BufferUtils.createByteBuffer(size);
|
ByteBuffer bibuf = BufferUtils.createByteBuffer(size);
|
||||||
FloatBuffer bwbuf = BufferUtils.createFloatBuffer(size);
|
FloatBuffer bwbuf = BufferUtils.createFloatBuffer(size);
|
||||||
|
|
||||||
for (WeightGroup group : _weightGroups) {
|
for (WeightGroup group : _weightGroups) {
|
||||||
byte[] indices = new byte[bonesPerVertex];
|
byte[] indices = new byte[4];
|
||||||
for (int ii = 0; ii < indices.length; ii++) {
|
for (int ii = 0; ii < 4; ii++) {
|
||||||
indices[ii] = (byte)((ii < group.bones.length) ?
|
indices[ii] = (byte)((ii < group.bones.length) ?
|
||||||
ListUtil.indexOf(_bones, group.bones[ii]) : 0);
|
ListUtil.indexOf(_bones, group.bones[ii]) : 0);
|
||||||
}
|
}
|
||||||
for (int ii = 0, widx = 0; ii < group.vertexCount; ii++) {
|
for (int ii = 0, widx = 0; ii < group.vertexCount; ii++) {
|
||||||
bibuf.put(indices);
|
bibuf.put(indices);
|
||||||
for (int jj = 0; jj < bonesPerVertex; jj++) {
|
for (int jj = 0; jj < 4; jj++) {
|
||||||
bwbuf.put((jj < group.bones.length) ? group.weights[widx++] : 0f);
|
bwbuf.put((jj < group.bones.length) ? group.weights[widx++] : 0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -640,17 +639,16 @@ public class SkinMesh extends ModelMesh
|
|||||||
bwbuf.rewind();
|
bwbuf.rewind();
|
||||||
|
|
||||||
GLSLShaderObjectsState sstate = _sconfig.getState();
|
GLSLShaderObjectsState sstate = _sconfig.getState();
|
||||||
sstate.setAttributePointer("boneIndices", bonesPerVertex, false, false, 0, bibuf);
|
sstate.setAttributePointer("boneIndices", 4, false, false, 0, bibuf);
|
||||||
sstate.setAttributePointer("boneWeights", bonesPerVertex, false, 0, bwbuf);
|
sstate.setAttributePointer("boneWeights", 4, false, 0, bwbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tracks the configuration of a skin shader. */
|
/** Tracks the configuration of a skin shader. */
|
||||||
protected static class SkinShaderConfig extends ShaderConfig
|
protected static class SkinShaderConfig extends ShaderConfig
|
||||||
{
|
{
|
||||||
public SkinShaderConfig (ShaderCache scache, int bonesPerVertex, boolean emissiveMapped)
|
public SkinShaderConfig (ShaderCache scache, boolean emissiveMapped)
|
||||||
{
|
{
|
||||||
super(scache);
|
super(scache);
|
||||||
_bonesPerVertex = bonesPerVertex;
|
|
||||||
_emissiveMapped = emissiveMapped;
|
_emissiveMapped = emissiveMapped;
|
||||||
|
|
||||||
// set bindings from texture units to samplers
|
// set bindings from texture units to samplers
|
||||||
@@ -662,11 +660,6 @@ public class SkinMesh extends ModelMesh
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBonesPerVertex ()
|
|
||||||
{
|
|
||||||
return _bonesPerVertex;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override // documentation inherited
|
@Override // documentation inherited
|
||||||
protected String getVertexShader ()
|
protected String getVertexShader ()
|
||||||
{
|
{
|
||||||
@@ -683,7 +676,6 @@ public class SkinMesh extends ModelMesh
|
|||||||
protected void getDefinitions (ArrayList<String> defs)
|
protected void getDefinitions (ArrayList<String> defs)
|
||||||
{
|
{
|
||||||
super.getDefinitions(defs);
|
super.getDefinitions(defs);
|
||||||
defs.add("BONES_PER_VERTEX " + _bonesPerVertex);
|
|
||||||
if (_emissiveMapped) {
|
if (_emissiveMapped) {
|
||||||
defs.add("EMISSIVE_MAPPED");
|
defs.add("EMISSIVE_MAPPED");
|
||||||
}
|
}
|
||||||
@@ -696,7 +688,6 @@ public class SkinMesh extends ModelMesh
|
|||||||
ddefs.add("MAX_BONE_COUNT " + MAX_SHADER_BONE_COUNT);
|
ddefs.add("MAX_BONE_COUNT " + MAX_SHADER_BONE_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int _bonesPerVertex;
|
|
||||||
protected boolean _emissiveMapped;
|
protected boolean _emissiveMapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -240,12 +240,8 @@ public abstract class ShaderConfig
|
|||||||
|
|
||||||
// add snippets for each of the lights
|
// add snippets for each of the lights
|
||||||
for (int ii = 0; ii < _lights.length; ii++) {
|
for (int ii = 0; ii < _lights.length; ii++) {
|
||||||
LightConfig light = _lights[ii];
|
String snippet = getLightSnippet(_lights[ii].type);
|
||||||
if (light.type == Light.LT_POINT) {
|
buf.append(snippet.replace("%", Integer.toString(ii)));
|
||||||
buf.append(POINT_LIGHT_SNIPPET.replace("%", Integer.toString(ii)));
|
|
||||||
} else if (light.type == Light.LT_DIRECTIONAL) {
|
|
||||||
buf.append(DIRECTIONAL_LIGHT_SNIPPET.replace("%", Integer.toString(ii)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the alpha value comes from the diffuse color in the material
|
// the alpha value comes from the diffuse color in the material
|
||||||
@@ -281,6 +277,21 @@ public abstract class ShaderConfig
|
|||||||
ddefs.add(buf.toString());
|
ddefs.add(buf.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a code snippet that adds the influence of a light of the specified type (after
|
||||||
|
* replacing '%' with the light index).
|
||||||
|
*/
|
||||||
|
protected String getLightSnippet (int type)
|
||||||
|
{
|
||||||
|
if (type == Light.LT_POINT) {
|
||||||
|
return POINT_LIGHT_SNIPPET;
|
||||||
|
} else if (type == Light.LT_DIRECTIONAL) {
|
||||||
|
return DIRECTIONAL_LIGHT_SNIPPET;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** The configuration of a single light in a {@link LightState}. */
|
/** The configuration of a single light in a {@link LightState}. */
|
||||||
protected static class LightConfig
|
protected static class LightConfig
|
||||||
implements Cloneable
|
implements Cloneable
|
||||||
|
|||||||
Reference in New Issue
Block a user