DirectX12结合Assimp实现骨骼动画时模型扭曲变形问题求助
DirectX12骨骼动画躯干手臂扭曲问题排查求助
我在基于DirectX12的C++游戏引擎中实现骨骼动画,使用Assimp库解析模型,运行时角色躯干和手臂出现扭曲变形。参照OpenGL教程实现,期望模型正常播放目标动画,但实际呈现扭曲状态(见附图)。已确认顶点与骨骼数据正确解析并上传,但应用动画时出现异常。
当使用m_LocalMatrix替代动画插值后的AnimatedTransform时,模型可正常渲染T姿势,但此时计算FinalTransformation需乘Offset矩阵。
动画实现代码
std::vector<FMatrix> LocalTransforms( m_SkeletalMesh->Joints.size() ); std::vector<FMatrix> ModelTransforms( m_SkeletalMesh->Joints.size() ); for (uint32 i = 0; i < m_SkeletalMesh->Joints.size(); i++) { FJoint& joint = m_SkeletalMesh->Joints[i]; if (m_anim->m_KeyFrames.find( joint.m_Name ) != m_anim->m_KeyFrames.end()) { uint32 KeyIndex = 0; uint32 NextKeyIndex = 0; for (uint32 i = 0; i < m_anim->m_KeyFrames[joint.m_Name].size() - 1; i++) { if (AnimationTimeTicks < m_anim->m_KeyFrames[joint.m_Name][i + 1].m_Timestamp) { KeyIndex = i; break; } } NextKeyIndex = KeyIndex + 1; float t1 = m_anim->m_KeyFrames[joint.m_Name][KeyIndex].m_Timestamp; float t2 = m_anim->m_KeyFrames[joint.m_Name][NextKeyIndex].m_Timestamp; float DeltaTime = t2 - t1; float Factor = (AnimationTimeTicks - (float)t1) / DeltaTime; HE_ASSERT( Factor >= 0.f && Factor <= 1.f ); FTransform& Start = m_anim->m_KeyFrames[joint.m_Name][KeyIndex].m_AnimatedTransform; FTransform& End = m_anim->m_KeyFrames[joint.m_Name][NextKeyIndex].m_AnimatedTransform; FTransform AnimatedTransform = FTransform::Interpolate( Start, End, Factor ); LocalTransforms[i] = AnimatedTransform.GetLocalMatrix(); } else { LocalTransforms[i] = joint.m_LocalMatrix; } } ModelTransforms[0] = LocalTransforms[0]; for (uint32 i = 1; i < m_SkeletalMesh->Joints.size(); i++) { FJoint& joint = m_SkeletalMesh->Joints[i]; ModelTransforms[i] = ModelTransforms[joint.m_ParentIndex] * LocalTransforms[i]; } JointCBData* pJointCB = m_SkeletalMesh->m_JointCB.GetBufferPointer(); for (uint32 i = 0; i < m_SkeletalMesh->Joints.size(); i++) { FJoint& joint = m_SkeletalMesh->Joints[i]; FMatrix& FinalTransform = pJointCB->kJoints[i]; FinalTransform = m_SkeletalMesh->m_GlobalInverseTransform * ModelTransforms[i]; }
骨骼层级解析代码
void ProcessJoints( std::vector<FJoint>& Joints, const aiNode* pNode, const uint32& ParentIndex, const aiMesh* pMesh ) { FJoint& joint = Joints.emplace_back(); strcpy_s( joint.m_Name, sizeof( joint.m_Name ), pNode->mName.C_Str()); joint.m_NameHash = StringHash( joint.m_Name ); joint.m_ParentIndex = ParentIndex; memcpy( &joint.m_LocalMatrix, &pNode->mTransformation, sizeof( FMatrix ) ); for (uint32 i = 0; i < pMesh->mNumBones; i++) { if (pNode->mName == pMesh->mBones[i]->mName) { memcpy( &joint.m_OffsetMatrix, &pMesh->mBones[i]->mOffsetMatrix, sizeof( FMatrix ) ); break; } } uint32 NewParentIndex = (uint32)Joints.size() - 1u; for (uint32 i = 0; i < pNode->mNumChildren; i++) { ProcessJoints( Joints, pNode->mChildren[i], NewParentIndex, pMesh ); } }
Shader代码(参考Frank Luna的DirectX12书籍)
float weights[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; weights[0] = Input.Weights[0]; weights[1] = Input.Weights[1]; weights[2] = Input.Weights[2]; weights[3] = 1.0f - weights[0] - weights[1] - weights[2]; float3 totalLocalPos = float3(0, 0, 0); for (int i = 0; i < HE_MAX_JOINTS_PER_VERTEX; i++) { totalLocalPos += weights[i] * mul( float4(Input.Position, 0), Joints[Input.JointIDs[i]] ).xyz; } Result.Position = mul( float4(totalLocalPos, 1), WorldViewProjection );
已尝试的解决方案
- 更新Assimp至最新版本
- 确保顶点数据类型正确
- 保证C++中矩阵为行主序、HLSL中为列主序
- 测试不同模型与动画,均出现相同扭曲问题
- 重新从Blender导出模型
该问题已困扰多周,恳请提供技术帮助!
内容的提问来源于stack exchange,提问作者GCourtney7
相关产品推荐
相关产品推荐

