Index: o3djs/effect.js |
=================================================================== |
--- o3djs/effect.js (revision 59332) |
+++ o3djs/effect.js (working copy) |
@@ -409,10 +409,11 @@ |
* @param {boolean} specular Whether to include stuff for diffuse |
* calculations. |
* @param {boolean} bumpSampler Whether there is a bump sampler. |
+ * @param {boolean} skinning Whether this mesh has a skin. |
* @return {string} The code for the declarations. |
*/ |
o3djs.effect.buildAttributeDecls = |
- function(material, diffuse, specular, bumpSampler) { |
+ function(material, diffuse, specular, bumpSampler, skinning) { |
var str = o3djs.effect.BEGIN_IN_STRUCT + |
o3djs.effect.ATTRIBUTE + o3djs.effect.FLOAT4 + ' ' + 'position' + |
o3djs.effect.semanticSuffix('POSITION') + ';\n'; |
@@ -420,6 +421,12 @@ |
str += o3djs.effect.ATTRIBUTE + o3djs.effect.FLOAT3 + ' ' + 'normal' + |
o3djs.effect.semanticSuffix('NORMAL') + ';\n'; |
} |
+ if (skinning) { |
+ str += o3djs.effect.ATTRIBUTE + o3djs.effect.FLOAT4 + ' influenceWeights' + |
+ o3djs.effect.semanticSuffix('BLENDWEIGHT') + ';\n'; |
+ str += o3djs.effect.ATTRIBUTE + o3djs.effect.FLOAT4 + ' influenceIndices' + |
+ o3djs.effect.semanticSuffix('BLENDINDICES') + ';\n'; |
+ } |
str += o3djs.effect.buildTexCoords(material, false) + |
o3djs.effect.buildBumpInputCoords(bumpSampler) + |
o3djs.effect.END_STRUCT; |
@@ -838,7 +845,22 @@ |
var p = o3djs.effect; |
var bumpSampler = material.getParam('bumpSampler'); |
var bumpUVInterpolant; |
+ var skinning; |
+ var maxSkinInfluences = 4; |
+ |
+ // Hardcode reasonable maximum for number of skinning uniforms. |
+ // glsl: Table 6.19: minimum MAX_VERTEX_UNIFORM_VECTORS is 128. |
+ // (DX9 requires a minimum of 256, so not a problem in o3d). |
+ var maxSkinUniforms = 36 * 3; |
+ if (o3djs.base.o3d && o3djs.base.o3d.SkinEval && |
+ o3djs.base.o3d.SkinEval.getMaxNumBones) { |
+ maxSkinUniforms = o3d.SkinEval.getMaxNumBones(material) * 3; |
+ skinning = true; |
+ } else { |
+ skinning = false; |
+ } |
+ |
/** |
* Extracts the texture type from a texture param. |
* @param {!o3d.ParamTexture} textureParam The texture parameter to |
@@ -906,6 +928,17 @@ |
}; |
/** |
+ * If skinning is enabled, builds the bone matrix uniform variables needed |
+ * for skinning. Otherwise, returns the empty string. |
+ * @return {string} The effect code for skinning uniforms. |
+ */ |
+ var buildSkinningUniforms = function() { |
+ return skinning ? 'uniform ' + p.FLOAT4 + ' boneToWorld3x4' + |
+ '[' + maxSkinUniforms + '];\n' + |
+ 'uniform float usingSkinShader;\n' : ''; |
+ }; |
+ |
+ /** |
* Builds uniform parameters for a given color input. If the material |
* has a sampler parameter, a sampler uniform is created, otherwise a |
* float4 color value is created. |
@@ -967,6 +1000,7 @@ |
var buildConstantShaderString = function(material, descriptions) { |
descriptions.push('constant'); |
return buildCommonVertexUniforms() + |
+ buildSkinningUniforms() + |
buildVertexDecls(material, false, false) + |
p.beginVertexShaderMain() + |
positionVertexShaderCode() + |
@@ -994,6 +1028,7 @@ |
descriptions.push('lambert'); |
return buildCommonVertexUniforms() + |
buildLightingUniforms() + |
+ buildSkinningUniforms() + |
buildVertexDecls(material, true, false) + |
p.beginVertexShaderMain() + |
p.buildUVPassthroughs(material) + |
@@ -1041,6 +1076,7 @@ |
descriptions.push('phong'); |
return buildCommonVertexUniforms() + |
buildLightingUniforms() + |
+ buildSkinningUniforms() + |
buildVertexDecls(material, true, true) + |
p.beginVertexShaderMain() + |
p.buildUVPassthroughs(material) + |
@@ -1099,6 +1135,7 @@ |
descriptions.push('phong'); |
return buildCommonVertexUniforms() + |
buildLightingUniforms() + |
+ buildSkinningUniforms() + |
buildVertexDecls(material, true, true) + |
p.beginVertexShaderMain() + |
p.buildUVPassthroughs(material) + |
@@ -1149,9 +1186,27 @@ |
* @return {string} The code for the vertex shader. |
*/ |
var positionVertexShaderCode = function() { |
- return ' ' + p.VERTEX_VARYING_PREFIX + 'position = ' + |
- p.mul(p.ATTRIBUTE_PREFIX + |
- 'position', 'worldViewProjection') + ';\n'; |
+ var attribute_position = p.ATTRIBUTE_PREFIX + 'position'; |
+ if (skinning) { |
+ return ' ' + p.FLOAT4 + ' weightedpos = ' + attribute_position + ';\n' + |
+ ' for (int i = 0; i < ' + maxSkinInfluences + '; i++) {\n' + |
+ ' ' + p.FLOAT4 + ' temp = ' + p.FLOAT4 + '(' + |
+ 'dot(boneToWorld3x4[int(influenceIndices[i] * 3.0)], ' + |
+ attribute_position + '),\n' + |
+ ' dot(boneToWorld3x4[int(influenceIndices[i] * 3.0 + 1.0)], ' + |
+ attribute_position + '),\n' + |
+ ' dot(boneToWorld3x4[int(influenceIndices[i] * 3.0 + 2.0)], ' + |
+ attribute_position + '),\n' + |
+ ' 1.0);\n' + |
+ ' weightedpos += usingSkinShader * influenceWeights[i] * ' + |
+ '(temp - ' + attribute_position + ');\n' + |
+ ' }\n' + |
+ ' ' + p.VERTEX_VARYING_PREFIX + 'position = ' + |
+ p.mul('weightedpos', 'worldViewProjection') + ';\n'; |
+ } else { |
+ return ' ' + p.VERTEX_VARYING_PREFIX + 'position = ' + |
+ p.mul(attribute_position, 'worldViewProjection') + ';\n'; |
+ } |
}; |
/** |
@@ -1159,10 +1214,29 @@ |
* @return {string} The code for the vertex shader. |
*/ |
var normalVertexShaderCode = function() { |
- return ' ' + p.VERTEX_VARYING_PREFIX + 'normal = ' + |
- p.mul(p.FLOAT4 + '(' + |
- p.ATTRIBUTE_PREFIX + |
- 'normal, 0)', 'worldInverseTranspose') + '.xyz;\n'; |
+ var attribute_normal = p.ATTRIBUTE_PREFIX + 'normal'; |
+ if (skinning) { |
+ return ' ' + p.FLOAT3 + ' weightednorm = ' + attribute_normal + ';\n' + |
+ ' for (int i = 0; i < ' + maxSkinInfluences + '; i++) {\n' + |
+ ' ' + p.FLOAT3 + ' temp = ' + p.FLOAT3 + '(' + |
+ 'dot(boneToWorld3x4[int(influenceIndices[i] * 3.0)].xyz, ' + |
+ attribute_normal + '),\n' + |
+ ' dot(boneToWorld3x4[int(influenceIndices[i] * 3.0 + 1.0)].xyz, ' + |
+ attribute_normal + '),\n' + |
+ ' dot(boneToWorld3x4[int(influenceIndices[i] * 3.0 + 2.0)].xyz, ' + |
+ attribute_normal + '));\n' + |
+ ' weightednorm += usingSkinShader * influenceWeights[i] * ' + |
+ '(temp - ' + attribute_normal + ');\n' + |
+ ' }\n' + |
+ ' ' + p.VERTEX_VARYING_PREFIX + 'normal = ' + |
+ p.mul(p.FLOAT4 + '(' + 'weightednorm' + ', 0)', |
+ 'worldInverseTranspose') + '.xyz;\n'; |
+ } else { |
+ return ' ' + p.VERTEX_VARYING_PREFIX + 'normal = ' + |
+ p.mul(p.FLOAT4 + '(' + |
+ attribute_normal + ', 0)', 'worldInverseTranspose') + |
+ '.xyz;\n'; |
+ } |
}; |
/** |
@@ -1238,7 +1312,7 @@ |
*/ |
var buildVertexDecls = function(material, diffuse, specular) { |
return p.buildAttributeDecls( |
- material, diffuse, specular, bumpSampler) + |
+ material, diffuse, specular, bumpSampler, skinning) + |
p.buildVaryingDecls( |
material, diffuse, specular, bumpSampler); |
}; |