- March 20, 2012 at 6:03 pm #30788
I made an animation in Blender 2.60 and successfully exported it to POD. It uses weight based skinning.
I loaded it into the Skinning Demo in the TrainingCourse folder.
Everything works fine but I am having some oddities in the vertex positions. Vertexes positions are near to be correct.
To obtain some detail I rotated some bones around their own axis. I’m not completely sure but it seems that this rotation is not well calculated by the vertex shader, or maybe ignored at all actually.
Thanks in advance for any help.
RMarch 21, 2012 at 4:35 pm #35587
With a better observation I saw that the problem might be where more than one bone has influence. I think the sum of the weighted bone matrices is not done properly in the vertex shader. Is this possible?
My weights are normalized so that for every vertex the sum of bones’ influences is always 1.0.March 21, 2012 at 4:47 pm #35588
Hi,Does your POD file look correct in PVRShaman? Also, how many bone influences do you have per-vertex? The OGLES2 Skinning example is setup for 3 bone influences. On a similar note what matrix palette size did you use? Again, the example expects a maximum size of 8. If you have more influences or more matrices in your palette the example will need to be tweaked to support all the skinning information.Thanks,ScottMarch 21, 2012 at 4:48 pm #35589
Here’s the code of the slightly modified vertex shader of the Skinning demo.
See the two bold lines before, where the vertex position and normal is calculated from all the bones influencing it.
If the current vertex is affected by bones then the vertex position and
normal will be transformed by the bone matrices. Each vertex wil have up
to 4 bone indices (inBoneIndex) and bone weights (inBoneWeights).
The indices are used to index into the array of bone matrices
(BoneMatrixArray) to get the required bone matrix for transformation. The
amount of influence a particular bone has on a vertex is determined by the
weights which should always total 1. So if a vertex is affected by 2 bones
the vertex position in world space is given by the following equation:
position = (BoneMatrixArray[Index0] * inVertex) * Weight0 +
Â (BoneMatrixArray[Index1] * inVertex) * Weight1
The same proceedure is applied to the normals but the translation part of
the transformation is ignored.
After this the position is multiplied by the view and projection matrices
only as the bone matrices already contain the model transform for this
particular mesh. The two-step transformation is required because lighting
will not work properly in clip space.
attribute highp vec3 inVertex;
attribute mediump vec3 inNormal;
attribute mediump vec2 inTexCoord;
attribute mediump vec4 inBoneIndex;
attribute mediump vec4 inBoneWeights;
uniform highp mat4 MVPMatrix;
uniform highp mat4 ViewProjMatrix;
uniform mediump vec3 LightDirModel;
uniform mediump vec3 LightDirWorld;
uniform mediump int BoneCount;
uniform highp mat4 BoneMatrixArray;
uniform highp mat3 BoneMatrixArrayIT;
varying lowp float LightIntensity;
varying mediump vec2 TexCoord;
varying mediump vec3 RSFactor;
// On PowerVR SGX it is possible to index the components of a vector
// with the  operator. However this can cause trouble with PC
// emulation on some hardware so we “rotate” the vectors instead.
mediump ivec4 boneIndex = ivec4(inBoneIndex);
mediump vec4 boneWeights = inBoneWeights;
if (BoneCount > 0)
highp mat4 boneMatrix = BoneMatrixArray[boneIndex.x];
mediump mat3 normalMatrix = BoneMatrixArrayIT[boneIndex.x];
highp vec4 position = boneMatrix * vec4(inVertex, 1.0) * boneWeights.x;
mediump vec3 worldNormal = normalMatrix * inNormal * boneWeights.x;
// PowerVR SGX supports uniforms in the for loop and nested conditionals.
// For performance reasons, the code below should be like this:
for (lowp int i = 1; i < BoneCount; ++i)
boneIndex = boneIndex.yzwx;
boneWeights = boneWeights.yzwx;
boneMatrix = BoneMatrixArray[boneIndex.x];
normalMatrix = BoneMatrixArrayIT[boneIndex.x];
if (boneWeights.x > 0.0)
position += boneMatrix * vec4(inVertex, 1.0) * boneWeights.x;
worldNormal += normalMatrix * inNormal * boneWeights.x;
// position += boneMatrix * vec4(inVertex, 1.0) * boneWeights.x; // ORIGINAL
// worldNormal += normalMatrix * inNormal * boneWeights.x; //ORIGINAL
// However this code causes a severe crash on PCEmulation
// in some ATI hardware due to a very limited loop support.
// If you are targeting SGX, please, modify the code below.
gl_Position = ViewProjMatrix * position;
// Simple diffuse lighting
LightIntensity = max(0.0, dot(normalize(worldNormal), -LightDirWorld));
gl_Position = MVPMatrix * vec4(inVertex, 1.0);
LightIntensity = max(0.0, dot(inNormal, -LightDirModel));
// Pass through texcoords
TexCoord = inTexCoord;
RSFactor = inNormal; // Test pass through
}riccardo_CS2012-03-21 16:52:37March 21, 2012 at 4:59 pm #35590
Thanks for your reply Scott.
I am using 3 bones influences. Also when I export I specify 3.
In PVRShaman I don’t see the model but I see it almost perfectly with animations and textures in the modded Skinning demo.
I’m not sure I understood what the limitation of 8 refers to. Does that mean I cannot have more than 8 bones in my armature/skeleton?riccardo_CS2012-03-21 16:59:49March 21, 2012 at 5:25 pm #35591
When you say you specifiy 3 is this via the “Matrix palette size” field in the “Skin” box? If so, this is the field where you should put the limit of 8. You’re correct in a way that this limits the number of bones that affects a mesh to be 8 but your armature/skeleton can have more than that in Blender. The exporter will just split the mesh into batches.March 21, 2012 at 5:25 pm #35592
Glad to say I found the problem. At one point during the my work I read around to try to export weights as RGBA and it kind of worked. I realized now that to export successfully from Blender (after having normalized weights) you need to export weights as unsigned bytes, normalized.
I attach the TXT resulting from saving the POD file exporter parameters (using PVRGeoPOD 1.27 beta) that work perfectly for me with Blender 2.60.
Hope this helps someone. Cheers!!