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:
Andrzej Kapolka
2007-05-15 00:55:19 +00:00
parent 124af1e0b1
commit c755fd626a
3 changed files with 34 additions and 46 deletions
+9 -23
View File
@@ -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