OpenGL 2下利用JointTransform矩阵计算蒙皮网格骨骼起止点的方法
实现步骤
1. 梳理骨骼基础数据
首先要明确每个骨骼的父骨骼索引,以及绑定姿态下骨骼的局部尾部位置(即骨骼自身原点指向末端的局部Vector3,可从模型骨骼数据提取,或自定义骨骼时直接设定)。
2. 计算骨骼世界空间起止点
起始点计算
- 根骨骼(父索引为-1):将其
JointTransform矩阵作用于局部原点(0,0,0),取变换结果的前三个分量作为世界空间起始点。 - 子骨骼:直接使用其父骨骼的结束点作为自身起始点,因为子骨骼的起点就是父骨骼的末端。
结束点计算
将骨骼的局部尾部位置转换为齐次坐标(x,y,z,1),乘以当前帧的JointTransform矩阵,取结果的前三个分量即为世界空间结束点。
3. OpenGL 2 绘制骨骼线条
准备顶点数据
按顺序将所有骨骼的起始点、结束点存入顶点数组,每两个顶点对应一条骨骼线段。
设置OpenGL状态
glDisable(GL_LIGHTING); // 禁用光照,避免影响线条显示 glLineWidth(2.0f); // 设置线条宽度,可按需调整 glColor3f(1.0f, 0.0f, 0.0f); // 设置线条颜色,示例为红色
执行绘制
glBegin(GL_LINES); for (int i = 0; i < boneCount; i++) { Vector3& start = boneStartPoints[i]; Vector3& end = boneEndPoints[i]; glVertex3f(start.x, start.y, start.z); glVertex3f(end.x, end.y, end.z); } glEnd();
关键代码示例
// 骨骼数据结构 struct Bone { int parentIndex; Vector3 localEndPos; Matrix4 jointTransform; }; vector<Bone> bones; vector<Vector3> boneStartPoints; vector<Vector3> boneEndPoints; // 计算所有骨骼的起止点 void calculateBonePositions() { boneStartPoints.clear(); boneEndPoints.clear(); for (int i = 0; i < bones.size(); i++) { Bone& bone = bones[i]; Vector3 startPos; if (bone.parentIndex == -1) { startPos = bone.jointTransform * Vector3(0, 0, 0); } else { startPos = boneEndPoints[bone.parentIndex]; } Vector3 endPos = bone.jointTransform * bone.localEndPos; boneStartPoints.push_back(startPos); boneEndPoints.push_back(endPos); } } // 绘制骨骼 void renderBones() { glDisable(GL_LIGHTING); glLineWidth(2.0f); glColor3f(1.0f, 0.0f, 0.0f); glBegin(GL_LINES); for (int i = 0; i < bones.size(); i++) { Vector3& s = boneStartPoints[i]; Vector3& e = boneEndPoints[i]; glVertex3f(s.x, s.y, s.z); glVertex3f(e.x, e.y, e.z); } glEnd(); // 恢复原有渲染状态(按需执行) glEnable(GL_LIGHTING); glLineWidth(1.0f); }
注意事项
- 确保
JointTransform是世界空间矩阵,若为局部空间矩阵,需通过父矩阵链式相乘转换为世界空间矩阵(根骨骼用自身矩阵,子骨骼为父骨骼世界矩阵乘自身局部矩阵)。 - 导入模型的骨骼局部尾部位置,可通过绑定姿态下父骨骼变换矩阵的逆矩阵,乘以子骨骼绑定姿态原点得到。
- 绘制前需设置正确的投影、视图矩阵,保证骨骼线条能正常显示在视口中。
内容的提问来源于stack exchange,提问作者thatGuy
相关产品推荐
相关产品推荐

