DirectX12 骨骼动画和 Assimp 库的问题

问题描述 投票:0回答:1

我正在尝试在我的游戏引擎中实现骨骼动画,但在使用 C++ 制作骨骼动画时遇到了问题。角色有动画,但躯干和手臂看起来扭曲。我正在关注 this OpenGL 教程,并期望模型看起来像 this,但它看起来像下面的视频。顶点和骨骼正在正确解析和上传,但是当我将动画应用于骨骼时,就会发生这种情况。

我已将所有骨骼组装到一个数组中,并保存它们的父级以完成骨骼层次结构,如this教程中所示。我相信问题出在此处,因为当我在第一个 for 循环中乘以 m_LocalMatrix 而不是 AnimatedTransform 时,模型以 T 姿势呈现 find 。但是,当我这样做时,在最后一个 for 循环中计算 FinalTransformation 矩阵时,我还必须乘以该骨骼的偏移矩阵。这是我的模型动画代码:

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

这也是我的着色器代码,取自 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 );

我几周来一直在努力解决这个问题,但就是找不到问题所在。任何帮助将不胜感激!

我尝试过但没有成功的其他事情是:

  1. 将 Assimp 更新到最新版本,认为可能是 Assimp 库的问题
  2. 确保顶点具有正确的数据类型,这是这个问题的解决方案
  3. 确保矩阵在 C++ 中以行优先,然后在 hlsl 中以列优先
  4. 不同的模型有不同的动画。我尝试的每个模型都有相同的拉伸/变形外观
  5. 从搅拌机重新导出相同的模型,因为我看到一些模型可能会导致问题,如this教程
c++ game-engine assimp directx-12 skeletal-animation
1个回答
0
投票

Assimp 主要面向 OpenGL,因此要使其与 DirectX 兼容,您必须进行一些调整。

Assimp::Importer::ReadFile()
中,传递 Assimp 后处理标志 -
aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder
。将属性 bool
AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS
设置为
true
并检查 - 使用函数
Assimp::Importer::SetPropertyBool()

您也可以通过此链接

© www.soinside.com 2019 - 2024. All rights reserved.