Hello,

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.

Any suggestions?

Thanks in advance for any help.

R

# Skinning and weights

**riccardo_cs**#1

**riccardo_cs**#2

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.

**Scott**#3

Hi,

**riccardo_cs**#4

**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[8];

uniform highp mat3 BoneMatrixArrayIT[8];

varying lowp float LightIntensity;

varying mediump vec2 TexCoord;

varying mediump vec3 RSFactor;

void main()

{

// 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;

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));

}

else

{

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:37

**riccardo_cs**#5

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:49

**Scott**#6

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.

**riccardo_cs**#7

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.

bFixedPoint=0

bFlipTextureV=0

bIndexed=1

bUnpackMatrix=0

bInterleaved=1

bSortVtx=1

bTangentSpace=0

cS=2

dwBoneLimit=3

ePrimType=0

eTriSort=1

exportBoneGeometry=0

exportControllers=1

bIndexAnimation=0

exportGeom=1

exportMatrices=1

exportMappingChannel=1

exportMaterials=1

bMerge=0

exportNormals=1

exportObjectSpace=1

exportSkin=1

exportSplines=0

exportVertexColor=1

fTangentSpaceVtxSplit=0.000000e+00

bAlignData=0

uiPadDataTo=4

psVcOptUVW[0].eType=1

psVcOptUVW[0].nEnable=131

psVcOptUVW[1].eType=1

psVcOptUVW[1].nEnable=131

psVcOptUVW[2].eType=1

psVcOptUVW[2].nEnable=131

psVcOptUVW[3].eType=1

psVcOptUVW[3].nEnable=131

psVcOptUVW[4].eType=1

psVcOptUVW[4].nEnable=131

psVcOptUVW[5].eType=1

psVcOptUVW[5].nEnable=131

psVcOptUVW[6].eType=1

psVcOptUVW[6].nEnable=131

psVcOptUVW[7].eType=1

psVcOptUVW[7].nEnable=131

staticFrame=0

sVcOptBin.eType=1

sVcOptBin.nEnable=135

sVcOptBoneInd.eType=13

sVcOptBoneInd.nEnable=15

sVcOptBoneWt.eType=15

sVcOptBoneWt.nEnable=15

sVcOptCol.eType=4

sVcOptCol.nEnable=15

sVcOptNor.eType=1

sVcOptNor.nEnable=135

sVcOptPos.eType=1

sVcOptPos.nEnable=135

sVcOptTan.eType=1

sVcOptTan.nEnable=135

Hope this helps someone. Cheers!!

**crescent**#8

It’s indeed helped ! I came to face the exact same problem,

<unsigned bytes, normalized>

Thanks riccardo_CS !