2016-01-13 96 views
0

我工作的一個項目搭建的網格骨頭已下列目標:Assimp:操縱手動

  • 負載操縱三維網格(如人的骨骼)與Assimp.NET
  • 操縱網格的骨頭這麼它適合你自己的身體(與微軟Kinect V2)
  • 執行頂點剝皮

加載着裝網和提取沒有任何問題(根據本教程骨信息工程(希望): http://www.richardssoftware.net/2013/10/skinned-models-in-directx-11-with.html)。每個骨(類 「ModelBone」)包括如下信息:

Assimp.Matrix4x4 LocalTransform 
Assimp.Matrix4x4 GlobalTransform 
Assimp.Matrix4x4 Offset 

LocalTransform直接從assimp節點(node.Transform)萃取。

GlobalTransform包括自己的LocalTransform和所有父母的LocalTransform(查看代碼剪輯calculateGlobalTransformation())。

Offset直接從assimp骨提取(bone.OffsetMatrix)。

目前我沒有實現GPU頂點蒙皮,但我遍歷每個頂點並操縱它的位置和法向量。

 foreach (Vertex vertex in this.Vertices) 
     { 
      Vector3D newPosition = new Vector3D(); 
      Vector3D newNormal = new Vector3D(); 

      for (int i=0; i < vertex.boneIndices.Length; i++) 
      { 
       int boneIndex = vertex.boneIndices[i]; 
       float boneWeight = vertex.boneWeights[i]; 

       ModelBone bone = this.BoneHierarchy.Bones[boneIndex]; 

       Matrix4x4 finalTransform = bone.GlobalTransform * bone.Offset; 

       // Calculate new vertex position and normal 
       newPosition += boneWeight * (finalTransform * vertex.originalPosition); 
       newNormal += boneWeight * (finalTransform * vertex.originalNormal); 
      } 

      // Apply new vertex position and normal 
      vertex.position = newPosition; 
      vertex.normal = newNormal; 
     } 

就像我已經說過的,我想操縱與Kinect的傳感器V2的骨頭,所以我不會用動畫(如關鍵幀插值,...)!但是一開始我希望能夠手動操作骨骼(例如,將網格的軀幹旋轉90度)。因此我通過調用Assimp.Matrix4x4.FromRotationX(1.5708f);創建一個4x4旋轉矩陣(圍繞x軸90度)。然後,我取代骨中的LocalTransform這個旋轉矩陣:

Assimp.Matrix4x4 rotation = Assimp.Matrix4x4.FromRotationX(1.5708f); 
bone.LocalTransform = rotation; 

UpdateTransformations(bone); 

我用下面的代碼來計算骨的新GlobalTransform骨操作後,它的孩子骨骼:

public void UpdateTransformations(ModelBone bone) 
    { 
     this.calculateGlobalTransformation(bone); 

     foreach (var child in bone.Children) 
     { 
      UpdateTransformations(child); 
     } 
    } 

    private void calculateGlobalTransformation(ModelBone bone) 
    { 
     // Global transformation includes own local transformation ... 
     bone.GlobalTransform = bone.LocalTransform; 

     ModelBone parent = bone.Parent; 

     while (parent != null) 
     { 
      // ... and all local transformations of the parent bones (recursively) 
      bone.GlobalTransform = parent.LocalTransform * bone.GlobalTransform; 
      parent = parent.Parent; 
     } 
    } 

這種做法的結果這image。該轉換似乎正確地應用於所有兒童骨骼,但被操縱的骨骼圍繞世界空間原點旋轉,而不是圍繞其自身的局部空間:(我已經嘗試將GlobalTransform翻譯(GlobalTransform的最後一行)包括到旋轉矩陣中它設置爲LocalTransform,但沒有成功......

我希望有人可以幫我解決這個問題

在此先感謝

回答

0

最後我找到了解決辦法:)所有的計算是正確的除外:

Matrix4x4 finalTransform = bone.GlobalTransform * bone.Offset; 

對我來說,正確的計算方法是:

Matrix4x4 finalTransform = bone.GlobalTransform * bone.Offset; 
finalTransform.transpose(); 

所以它似乎是一個行 - 主要/列 - 主要問題。我的最終CPU頂點蒙皮代碼是:

public void PerformSmoothVertexSkinning() 
    { 
     // Precompute final transformation matrix for each bone 
     List<Matrix4x4> FinalTransforms = new List<Matrix4x4>(); 

     foreach (ModelBone bone in this.BoneHierarchy.Bones) 
     { 
      // Multiplying a vector (e.g. vertex position/normal) by finalTransform will (from right to left): 
      //  1. transform the vector from mesh space to bone space (by bone.Offset) 
      //  2. transform the vector from bone space to world space (by bone.GlobalTransform) 
      Matrix4x4 finalTransform = bone.GlobalTransform * bone.Offset; 
      finalTransform.Transpose(); 

      FinalTransforms.Add(finalTransform); 
     } 

     foreach (Submesh submesh in this.Submeshes) 
     { 
      foreach (Vertex vertex in submesh.Vertices) 
      { 
       Vector3D newPosition = new Vector3D(); 
       Vector3D newNormal = new Vector3D(); 

       for (int i = 0; i < vertex.BoneIndices.Length; i++) 
       { 
        int boneIndex = vertex.BoneIndices[i]; 
        float boneWeight = vertex.BoneWeights[i]; 

        // Get final transformation matrix to transform each vertex position 
        Matrix4x4 finalVertexTransform = FinalTransforms[boneIndex]; 

        // Get final transformation matrix to transform each vertex normal (has to be inverted and transposed!) 
        Matrix4x4 finalNormalTransform = FinalTransforms[boneIndex]; 
        finalNormalTransform.Inverse(); 
        finalNormalTransform.Transpose(); 

        // Calculate new vertex position and normal (average of influencing bones) 
        // Formula: newPosition += boneWeight * (finalVertexTransform * vertex.OriginalPosition); 
        //      += boneWeight * (bone.GlobalTransform * bone.Offset * vertex.OriginalPosition); 
        // From right to left: 
        //  1. Transform vertex position from mesh space to bone space (by bone.Offset) 
        //  2. Transform vertex position from bone space to world space (by bone.GlobalTransform) 
        //  3. Apply bone weight 
        newPosition += boneWeight * (finalVertexTransform * vertex.OriginalPosition); 
        newNormal += boneWeight * (finalNormalTransform * vertex.OriginalNormal); 
       } 

       // Apply new vertex position and normal 
       vertex.Position = newPosition; 
       vertex.Normal = newNormal; 
      } 
     } 
    } 

希望這個線程對其他人有幫助。感謝您的幫助謝爾蓋!

0

要改變你應該使用它的偏移矩陣骨:! http://assimp.sourceforge.net/lib_html/structai_bone.html#a9ae5293b5c937436e4b338e20221cc2e 偏移矩陣從全局變換步入骨骼空間。如果你想旋轉骨圍繞它的起源,你應該:

  1. 轉化爲骨空間
  2. 應用旋轉
  3. 轉化爲

所以骨骼的全球變換可以這樣來計算的全球空間:

bonesGlobalTransform = parentGlobalTransform * 
     bone.offset.inverse() * 
     boneLocalTransform * 
     bone.offset; 

所以:

  1. 轉化爲骨空間偏移矩陣
  2. 應用本地變換
  3. 轉變爲全球空間offset.inverse()矩陣
+0

嗨。我認爲既計算GlobalTransformation和頂點蒙皮也是不正確的 你應該在calculateGlobalTransformation中使用偏移矩陣並且不應該在頂點蒙皮中使用 –

+0

Hey Sergey,我很高興你回答。幾乎放棄了這個話題。自從我上一篇文章以來,我改變了兩件小事(矩陣乘法順序)。所以我已經更新了我的初始文章(請參閱'calculateGlobalTransformation'和頂點蒙皮代碼),它現在反映了我當前的代碼。我確定'GlobalTransform'的計算是正確的,因爲當在我的視口中顯示每個骨骼的GlobalTransform的轉換部分作爲點時,它會生成以下圖像:http://goo.gl/ncBSF4。所以我認爲這個問題是皮膚問題(例如'FinalTransform'錯誤)。 – wombat

+0

在我的回答中,您可以看到骨骼的GlobalTransform的計算。 你不需要FinalTransform。您應該使用GlobalTransform來轉換頂點。 喜歡這個問題: 'resultVertexTransformation + = m_bonesGlobalTransforms [boneIdx] * boneWeight;' –