顶点蒙皮过程

骨骼的运动和顶点蒙皮是不同的两个过程,骨骼的运动比较简单,就不详细说了。

先贴一下顶点计算公式:

 1 VertexPos = MJ-0 * weight[index0].pos * weight[index0].weight+ ... + MJ-N * weight[indexN].pos * weight[indexN].weight; 

先解释一下变量意思:

MJ-0:权重关联到的骨骼的矩阵

weight[index0].pos 权重偏移量

weight[index0].weight 权重比率

一个顶点可以关联到N个权重,一般我们在m5模型中会限制在4个以内,所有权重值的和为1,权重偏移量就是相对的关联骨骼的位置。具体实现代码:

 1 VGAVertex renderVertex = { 0,0,0, static_cast<float>(uv[0]),static_cast<float>(uv[1]) };
 2 
 3 for (int j = 0; j < pMd5Vertex->weightCount; j++)
 4 {
 5     shared_ptr<Weight> weight = weights[pMd5Vertex->weightIndex + j];
 6 
 7 //    shared_ptr<FrameJoint> joint = frame->jointVec[weight->jointIndex];
 8 
 9     shared_ptr<Md5Joint> md5Joint = jointVec[weight->jointIndex];
10 
11     //FbxVector4 wv = joint->m_worldMatrix.MultT(weight->weightPos);
12 
13     FbxVector4 wv = md5Joint->bindMatrix.MultT(weight->weightPos);
14 
15     //wv += joint.m_Pos;
16 
17     wv *= weight->weight;
18 
19     renderVertex.x += static_cast<float>(wv[0]);//joint.m_Pos[0] + wv[0]
20     renderVertex.y += static_cast<float>(wv[1]);
21     renderVertex.z += static_cast<float>(wv[2]);
22 }

这里传入bindpose下或动画中的矩阵就能分别显示不同的模型,这是第一种算法。

第二种算法使用bindpose下的顶点来计算当前顶点。假定顶点关联的权重只有一个的时候,最终顶点 = 骨骼矩阵*权重偏移量,所以根据公式,我们需要先求出权重偏移量,权重偏移量 = 反转骨骼矩阵 * 最终顶点,代入上面的公式就是:

 VertexPos = (MJ-0 * MJ-0(bindpose)-1)* VertexPosbindpose * weight[index0].weight+ ... + (MJ-N * MJ-N(bindpose)-1)* VertexPosbindpose * weight[indexN].weight ; 

这种情况下,我们就不需要权重偏移量,需要最终顶点和bindpose下的骨骼反向矩阵。

第一种如果要显示静态模型,也得当按动画一样来计算,而且不需要保存最终顶点。而第二种在不需要动画的时候能显示静态模型,但是计算量会增加,因为多了一个骨骼逆矩阵,away3d中就是这样的计算方法。

 1 for (size_t i = 0; i < vertexCount; i++)
 2 {
 3     shared_ptr<Md5Vertex> pMd5Vertex = vertices[i];
 4 
 5     FbxVector2 uv;
 6     //if (useIndex)
 7     //    uv = pMesh->GetElementUV()->GetDirectArray().GetAt(pMd5Vertex->uvIndex);
 8     //else
 9     uv = pMd5Vertex->uv;
10 
11     VGAVertex bindposeVertex = m_pVertices[i];
12 
13     FbxVector4 bindposeVertexVec4 = FbxVector4(bindposeVertex.x, bindposeVertex.y, bindposeVertex.z);//bindpose最终顶点
14 
15     VGAVertex renderVertex = { 0,0,0, bindposeVertex.u,bindposeVertex.v };
16 
17 
18     for (int j = 0; j < pMd5Vertex->weightCount; j++)
19     {
20         shared_ptr<Weight> weight = weights[pMd5Vertex->weightIndex + j];
21 
22         shared_ptr<FrameJoint> joint = frame->jointVec[weight->jointIndex];
23 
24         shared_ptr<Md5Joint> md5Joint = jointVec[weight->jointIndex];
25 
26         FbxAMatrix invMatrix = md5Joint->bindMatrix.Inverse();
27         FbxVector4 wv = invMatrix.MultT(bindposeVertexVec4); 
28 
29         //wv += joint.m_Pos;
30 
31         wv = joint->m_worldMatrix.MultT(wv); //此处wv = weight->weightPos
32 
33         //wv = joint->m_worldMatrix.MultT(weight->weightPos);
34 
35         wv *= weight->weight;
36 
37         renderVertex.x += static_cast<float>(wv[0]);//joint.m_Pos[0] + wv[0]
38         renderVertex.y += static_cast<float>(wv[1]);
39         renderVertex.z += static_cast<float>(wv[2]);
40     }
41 
42     *pVertices = renderVertex;
43     pVertices++;
44 }

可以将骨骼当前矩阵先乘上bindpose的逆矩阵,

1 FbxAMatrix invMatrix = md5Joint->bindMatrix.Inverse();
2 FbxVector4 wv = (joint->m_worldMatrix * invMatrix).MultT(bindposeVertexVec4);
原文地址:https://www.cnblogs.com/riaol/p/5691599.html