2016-08-06 16 views
2

Я пытаюсь реализовать скелетную анимацию с помощью Assimp.net и OpenTK и слежу за этим tutorial, но я не могу заставить его работать.Skinning with Assimp.Net и OpenTK

Модель кажется тонкой с идентичными матрицами, но ужасно искажена при использовании преобразований, которые я генерирую из Assimp.

Я подозреваю, что проблема заключается в том, как я совмещаю все матрицы или что в OpenTK есть разница, которую я не понимаю. У меня есть аналогичные корректировки из учебника, как предлагается здесь: Matrix calculations for gpu skinning

, но он по-прежнему искажен, по-другому, я также попытался преобразовать все матрицы Ассимпа в матрицы OpenTK до выполнения любого умножения. Эти участки кода, связанные с матрицами, я могу предоставить больше, если необходимо:

Матрица преобразования

public static OpenTK.Matrix4 TKMatrix(Assimp.Matrix4x4 input) 
    { 
     return new OpenTK.Matrix4(input.A1, input.B1, input.C1, input.D1, 
            input.A2, input.B2, input.C2, input.D2, 
            input.A3, input.B3, input.C3, input.D3, 
            input.A4, input.B4, input.C4, input.D4); 
    } 

Сохранение глобальной обратной

public class LoaderMesh 
    { 
    public Scene mScene; 
    public Mesh mMesh; 

    public OpenTK.Matrix4 GlobalInverseTransform { get; set; } 

    public LoaderMesh(Scene aiScene, Mesh aiMesh) 
    { 
     mScene = aiScene; 
     mMesh = aiMesh; 

     GlobalInverseTransform = Util.TKMatrix(mScene.RootNode.Transform); 
     GlobalInverseTransform.Invert(); 
    } 

Загрузка кости

public void LoadBones(List<VBO.Vtx_BoneWeight.Vtx> boneData) 
    { 
     for (uint iBone = 0; iBone < mMesh.BoneCount; ++iBone) 
     { 
      uint boneIndex = 0; 
      String bonename = mMesh.Bones[iBone].Name; 

      if (!BoneMapping.ContainsKey(bonename)) 
      { 
       boneIndex = (uint)NumBones; 
       NumBones++; 
       BoneInfo bi = new BoneInfo(); 
       BoneInfos.Add(bi); 
      } 
      else 
      { 
       boneIndex = BoneMapping[bonename]; 
      } 

      BoneMapping[bonename] = boneIndex; 
      BoneInfos[(int)boneIndex].OffsetMatrix = Util.TKMatrix(mMesh.Bones[iBone].OffsetMatrix); 

      for (uint iWeight = 0; iWeight < mMesh.Bones[iBone].VertexWeightCount; iWeight++) 
      { 
       uint VertexID = /*m_Entries[MeshIndex].BaseVertex*/ mMesh.Bones[iBone].VertexWeights[iWeight].VertexID; 
       float Weight = mMesh.Bones[iBone].VertexWeights[iWeight].Weight; 

       VBO.Vtx_BoneWeight.Vtx vtx = boneData[(int)VertexID]; 

       VBO.Vtx_BoneWeight.AddWeight(ref vtx, boneIndex, Weight); 

       boneData[(int)VertexID] = vtx; 
      } 
     } 
    } 

Расчет трансформации

public void ReadNodeHierarchy(float animationTime, Node aiNode, ref OpenTK.Matrix4 parentTransform) 
    { 
     String NodeName = aiNode.Name; 

     Animation animation = mScene.Animations[0]; 

     OpenTK.Matrix4 NodeTransformation = Util.TKMatrix(aiNode.Transform); 

     NodeAnimationChannel nodeAnim = FindNodeAnim(animation, NodeName); 

     OpenTK.Matrix4 localTransform = OpenTK.Matrix4.Identity; 

     if (nodeAnim != null) 
     { 
      // Interpolate scaling and generate scaling transformation matrix 
      Vector3D Scaling = new Vector3D(); 
      CalcInterpolatedScaling(ref Scaling, animationTime, nodeAnim); 
      Console.WriteLine("Scaling: " + Scaling.ToString()); 
      OpenTK.Matrix4 ScalingM = Util.TKMatrix(Matrix4x4.FromScaling(Scaling)); 

      // Interpolate rotation and generate rotation transformation matrix 
      Quaternion RotationQ = new Quaternion(); 
      CalcInterpolatedRotation(ref RotationQ, animationTime, nodeAnim); 
      Console.WriteLine("Rotation: " + RotationQ.ToString()); 
      OpenTK.Matrix4 RotationM = Util.TKMatrix(RotationQ.GetMatrix()); 

      // Interpolate translation and generate translation transformation matrix 
      Vector3D Translation = new Vector3D(); 
      CalcInterpolatedPosition(ref Translation, animationTime, nodeAnim); 
      Console.WriteLine("Transform: " + Translation.ToString()); 
      OpenTK.Matrix4 TranslationM = Util.TKMatrix(Matrix4x4.FromTranslation(Translation)); 

      // Combine the above transformations 
      NodeTransformation = TranslationM * RotationM * ScalingM; 

      localTransform = TranslationM * RotationM * ScalingM; 
     } 

     OpenTK.Matrix4 GlobalTransformation = parentTransform * NodeTransformation; 

     OpenTK.Matrix4 parentPass = OpenTK.Matrix4.Identity; 
     if (BoneMapping.ContainsKey(NodeName) == true) 
     { 
      uint BoneIndex = BoneMapping[NodeName]; 
      //BoneInfos[(int)BoneIndex].FinalTransformation = GlobalInverseTransform * BoneInfos[(int)BoneIndex].OffsetMatrix * GlobalTransformation; 
      BoneInfos[(int)BoneIndex].NodeTransformation = parentTransform * Util.TKMatrix(aiNode.Transform) * localTransform; 
      parentPass = BoneInfos[(int)BoneIndex].NodeTransformation; 

      BoneInfos[(int)BoneIndex].FinalTransformation = GlobalInverseTransform * BoneInfos[(int)BoneIndex].NodeTransformation * BoneInfos[(int)BoneIndex].OffsetMatrix; 
     } 

     for (uint i = 0; i < aiNode.ChildCount; i++) 
     { 
      ReadNodeHierarchy(animationTime, aiNode.Children[i], ref parentPass); 
     } 
    } 

И это есть код вершинного шейдера

#version 400 

layout(location = 0)in vec4 vert; 
layout(location = 1)in vec4 normal; 
layout(location = 2)in vec4 texCoord; 
layout(location = 3)in vec4 tanCoord; 

layout(location = 4)in ivec4 boneIDs; 
layout(location = 5)in vec4 boneWeights; 

uniform mat4 projectionMtx; 
uniform mat4 viewMtx; 
uniform mat4 modelMtx; 

const int MAX_BONES = 100; 

uniform mat4 bones[MAX_BONES]; 

out vec3 positionFrg_CS; 
out vec3 normalFrg_CS; 
out vec3 tanCoordFrg_CS; 
out vec3 bitCoordFrg_CS; 
out vec4 texCoordFrg; 

void main() 
{ 
    mat4 BoneTransform = bones[boneIDs[0]] * boneWeights[0]; 
    BoneTransform += bones[boneIDs[1]] * boneWeights[1]; 
    BoneTransform += bones[boneIDs[2]] * boneWeights[2]; 
    BoneTransform += bones[boneIDs[3]] * boneWeights[3]; 

    gl_Position = projectionMtx * viewMtx * modelMtx * BoneTransform * vert; 


} 

ли что-то я делаю неправильно перемножения матриц вместе?

+0

Я бы предложил проверить, чтобы ваши основные столбцы и основные матрицы соответствовали друг другу. У меня была проблема, когда я поместил код OGLDev в свой собственный конвейер, и я использовал основные матрицы столбцов, в то время как они использовали ряд строк, и он все испортил. –

+0

Вам повезло с этим? –

+0

@livin_amuk Да, у меня это работает. Я отправил ответ с исправленным источником и несколькими заметками. Я могу расширить это, если это необходимо. – ArThor

ответ

3

В ответ на livin_amuk, я получил эту работу, по крайней мере, достаточно хорошо для моих потребностей, но я это исправил 6 месяцев назад, и память у меня смутная ...

Если я правильно помню, мой основной вопрос был индексы костей/вершин, я думаю, что я испортил BaseVertex, потому что я был в спешке. Вот моя текущая рабочая функция LoadBones.

public void LoadBones(List<VBO.Vtx_BoneWeight.Vtx> boneData, SubMesh mesh) 
    { 
    for (int iBone = 0; iBone < mesh.mMesh.BoneCount; ++iBone) 
    { 
     uint boneIndex = 0; 
     String bonename = mesh.mMesh.Bones[iBone].Name; 

     if (!BoneMapping.ContainsKey(bonename)) 
     { 
      boneIndex = (uint)NumBones; 
      NumBones++; 
      BoneInfo bi = new BoneInfo(); 
      BoneInfos.Add(bi); 

//Note, I have these two lines included inside the if statement, the original tut does not. Not sure if it makes a difference. 
      BoneMapping[bonename] = boneIndex; 
      BoneInfos[(int)boneIndex].OffsetMatrix = AssimpToOpenTK.TKMatrix(mesh.mMesh.Bones[iBone].OffsetMatrix); 
     } 
     else 
     { 
      boneIndex = BoneMapping[bonename]; 
     } 

     for (int iWeight = 0; iWeight < mesh.mMesh.Bones[iBone].VertexWeightCount; iWeight++) 
     { 
//My question has the mesh.BaseVertex commented out. it is important! 
      long VertexID = mesh.BaseVertex + mesh.mMesh.Bones[iBone].VertexWeights[iWeight].VertexID; 
      float Weight = mesh.mMesh.Bones[iBone].VertexWeights[iWeight].Weight; 

      VBO.Vtx_BoneWeight.Vtx vtx = boneData[(int)VertexID]; 

      VBO.Vtx_BoneWeight.AddWeight(ref vtx, boneIndex, Weight); 

      boneData[(int)VertexID] = vtx; 
     } 
    } 
    } 

У меня также были преобразования назад. Функция чтения иерархии узлов.

public void ReadNodeHierarchy(float animationTime, Node aiNode, ref OpenTK.Matrix4 parentTransform) 
    { 
    String NodeName = aiNode.Name; 

    Animation animation = mScene.Animations[0]; 

    OpenTK.Matrix4 NodeTransformation = AssimpToOpenTK.TKMatrix(aiNode.Transform); 

    NodeAnimationChannel nodeAnim = FindNodeAnim(animation, NodeName); 

    if (nodeAnim != null) 
    { 
     // Interpolate scaling and generate scaling transformation matrix 
     Vector3D Scaling = new Vector3D(); 
     CalcInterpolatedScaling(ref Scaling, animationTime, nodeAnim); 
     OpenTK.Matrix4 ScalingM = AssimpToOpenTK.TKMatrix(Matrix4x4.FromScaling(Scaling)); 

     // Interpolate rotation and generate rotation transformation matrix 
     Quaternion RotationQ = new Quaternion(); 
     CalcInterpolatedRotation(ref RotationQ, animationTime, nodeAnim); 
     OpenTK.Matrix4 RotationM = AssimpToOpenTK.TKMatrix(RotationQ.GetMatrix()); 

     // Interpolate translation and generate translation transformation matrix 
     Vector3D Translation = new Vector3D(); 
     CalcInterpolatedPosition(ref Translation, animationTime, nodeAnim); 
     OpenTK.Matrix4 TranslationM = AssimpToOpenTK.TKMatrix(Matrix4x4.FromTranslation(Translation)); 

     // Combine the above transformations 
     //All that local transform stuff is gone. The order of the transforms is reversed from my question AND the original tut. 
     NodeTransformation = ScalingM * RotationM * TranslationM; 
    } 
//Also reversed. 
    OpenTK.Matrix4 GlobalTransformation = NodeTransformation * parentTransform; 

    //GlobalTransformation = OpenTK.Matrix4.Identity; 
    if (BoneMapping.ContainsKey(NodeName) == true) 
    { 
     uint BoneIndex = BoneMapping[NodeName]; 
//Also, Also, reversed. 
     BoneInfos[(int)BoneIndex].FinalTransformation = BoneInfos[(int)BoneIndex].OffsetMatrix * GlobalTransformation * GlobalInverseTransform; 
    } 

    for (int i = 0; i < aiNode.ChildCount; i++) 
    { 
     ReadNodeHierarchy(animationTime, aiNode.Children[i], ref GlobalTransformation); 
    } 
    } 

Преобразование матрицы в верхней части также верно, равно как и код шейдера.