2016-09-22 41 views
6

最近私はボーンアニメーションのインポートに取り組んでいます。そのため、Iimpテクニックを使用した3Dミニクラフトのようなモデルを作成し、Assimpアニメーションのインポートをテストしました。出力フォーマットはCOLLADA(*。dae)で、私が使用したツールはBlenderです。プログラミング面では、私の環境はopengl/glm/assimpです。私の問題のこれらの情報は十分だと思います.1つは、モデルのアニメーション、私はちょうどassimpアニメーションをテストするための7 unmoveキーフレームを記録します。Assimpアニメーションボーン変換

まず、ローカル変換部分以外の変換は正しいと思いますので、関数はglm::mat4(1.0f)のみを返し、結果はバインドポーズ(不明)モデルを返します。 (下図参照)

第2に、値glm::mat4(1.0f)bone->localTransform = transform * scaling * glm::mat4(1.0f);に戻すと、モデルが変形します。 test and originbone->localTransform = glm::mat4(1.0f) * scaling * rotate;:この画像は:(地面の下にある)

ここでコード:ブレンダーで

テスト画像とモデル(画像下記参照)

void MeshModel::UpdateAnimations(float time, std::vector<Bone*>& bones) 
{ 
    for each (Bone* bone in bones) 
    { 
     glm::mat4 rotate = GetInterpolateRotation(time, bone->rotationKeys); 
     glm::mat4 transform = GetInterpolateTransform(time, bone->transformKeys); 
     glm::mat4 scaling = GetInterpolateScaling(time, bone->scalingKeys); 
     //bone->localTransform = transform * scaling * glm::mat4(1.0f); 
     //bone->localTransform = glm::mat4(1.0f) * scaling * rotate; 
     //bone->localTransform = glm::translate(glm::mat4(1.0f), glm::vec3(0.5f)); 
     bone->localTransform = glm::mat4(1.0f); 
    } 
} 

void MeshModel::UpdateBone(Bone * bone) 
{ 
    glm::mat4 parentTransform = bone->getParentTransform(); 
    bone->nodeTransform = parentTransform 
     * bone->transform // assimp_node->mTransformation 
     * bone->localTransform; // T S R matrix 

    bone->finalTransform = globalInverse 
     * bone->nodeTransform 
     * bone->inverseBindPoseMatrix; // ai_mesh->mBones[i]->mOffsetMatrix 

    for (int i = 0; i < (int)bone->children.size(); i++) { 
     UpdateBone(bone->children[i]); 
    } 
} 

glm::mat4 Bone::getParentTransform() 
{ 
    if (this->parent != nullptr) 
     return parent->nodeTransform; 
    else 
     return glm::mat4(1.0f); 
} 

glm::mat4 MeshModel::GetInterpolateRotation(float time, std::vector<BoneKey>& keys) 
{ 
    // we need at least two values to interpolate... 
    if ((int)keys.size() == 0) { 
     return glm::mat4(1.0f); 
    } 
    if ((int)keys.size() == 1) { 
     return glm::mat4_cast(keys[0].rotation); 
    } 

    int rotationIndex = FindBestTimeIndex(time, keys); 
    int nextRotationIndex = (rotationIndex + 1); 
    assert(nextRotationIndex < (int)keys.size()); 
    float DeltaTime = (float)(keys[nextRotationIndex].time - keys[rotationIndex].time); 
    float Factor = (time - (float)keys[rotationIndex].time)/DeltaTime; 
    if (Factor < 0.0f) 
     Factor = 0.0f; 
    if (Factor > 1.0f) 
     Factor = 1.0f; 
    assert(Factor >= 0.0f && Factor <= 1.0f); 
    const glm::quat& startRotationQ = keys[rotationIndex].rotation; 
    const glm::quat& endRotationQ = keys[nextRotationIndex].rotation; 
    glm::quat interpolateQ = glm::lerp(endRotationQ, startRotationQ, Factor); 
    interpolateQ = glm::normalize(interpolateQ); 
    return glm::mat4_cast(interpolateQ); 
} 

glm::mat4 MeshModel::GetInterpolateTransform(float time, std::vector<BoneKey>& keys) 
{ 
    // we need at least two values to interpolate... 
    if ((int)keys.size() == 0) { 
     return glm::mat4(1.0f); 
    } 
    if ((int)keys.size() == 1) { 
     return glm::translate(glm::mat4(1.0f), keys[0].vector); 
    } 

    int translateIndex = FindBestTimeIndex(time, keys); 
    int nextTranslateIndex = (translateIndex + 1); 
    assert(nextTranslateIndex < (int)keys.size()); 
    float DeltaTime = (float)(keys[nextTranslateIndex].time - keys[translateIndex].time); 
    float Factor = (time - (float)keys[translateIndex].time)/DeltaTime; 
    if (Factor < 0.0f) 
     Factor = 0.0f; 
    if (Factor > 1.0f) 
     Factor = 1.0f; 
    assert(Factor >= 0.0f && Factor <= 1.0f); 
    const glm::vec3& startTranslate = keys[translateIndex].vector; 
    const glm::vec3& endTrabslate = keys[nextTranslateIndex].vector; 
    glm::vec3 delta = endTrabslate - startTranslate; 
    glm::vec3 resultVec = startTranslate + delta * Factor; 
    return glm::translate(glm::mat4(1.0f), resultVec); 
} 

をコードアイデアが参照されMatrix calculations for gpu skinningSkeletal Animation With Assimp

全体として、私はassimpからのすべての情報をMeshModelにフェッチして骨構造に保存しますが、情報は問題ないと思いますか?

最後の事、私の頂点シェーダコード:

#version 330 core 
#define MAX_BONES_PER_VERTEX 4 

in vec3 position; 
in vec2 texCoord; 
in vec3 normal; 
in ivec4 boneID; 
in vec4 boneWeight; 

const int MAX_BONES = 100; 

uniform mat4 model; 
uniform mat4 view; 
uniform mat4 projection; 
uniform mat4 boneTransform[MAX_BONES]; 

out vec3 FragPos; 
out vec3 Normal; 
out vec2 TexCoords; 
out float Visibility; 

const float density = 0.007f; 
const float gradient = 1.5f; 

void main() 
{ 
    mat4 boneTransformation = boneTransform[boneID[0]] * boneWeight[0]; 
    boneTransformation += boneTransform[boneID[1]] * boneWeight[1]; 
    boneTransformation += boneTransform[boneID[2]] * boneWeight[2]; 
    boneTransformation += boneTransform[boneID[3]] * boneWeight[3]; 


    vec3 usingPosition = (boneTransformation * vec4(position, 1.0)).xyz; 
    vec3 usingNormal = (boneTransformation * vec4(normal, 1.0)).xyz; 

    vec4 viewPos = view * model * vec4(usingPosition, 1.0); 
    gl_Position = projection * viewPos; 
    FragPos = vec3(model * vec4(usingPosition, 1.0f)); 
    Normal = mat3(transpose(inverse(model))) * usingNormal; 
    TexCoords = texCoord; 
    float distance = length(viewPos.xyz); 
    Visibility = exp(-pow(distance * density, gradient)); 
    Visibility = clamp(Visibility, 0.0f, 1.0f); 
} 

上記の私の質問の場合、コードの欠如や漠然と説明し、おかげで、私に知らせてください!

編集:このような追加的な、私の骨の情報(コードフェッチ部分)では(1)

for (int i = 0; i < (int)nodeAnim->mNumPositionKeys; i++) 
{ 
    BoneKey key; 
    key.time = nodeAnim->mPositionKeys[i].mTime; 
    aiVector3D vec = nodeAnim->mPositionKeys[i].mValue; 
    key.vector = glm::vec3(vec.x, vec.y, vec.z); 
    currentBone->transformKeys.push_back(key); 
} 

は、いくつかの形質転換ベクターを持っていたのでglm::mat4 transform = GetInterpolateTransform(time, bone->transformKeys);上記の私のコード、Absloutely、取得と同じ値です。私は変換値が真であるかどうかを指定するnomoveキーフレームアニメーションを作成したかどうかはわかりません(もちろん7つのキーフレームがあります)。

このようなキーフレームのコンテンツ(頭骨のデバッグ): keyframe from head 7つの異なるキーフレーム、同じベクトル値。

編集:あなたは私のDAEファイルをテストする場合(2)

を、私は、jsfiddleに入れて来て、それを取る:)。もう一つ、ユニティで私のファイルが正しく動作するので、おそらく私のローカル変換が問題を起こしていないと思われます。問題はparentTransformやbone-> transform ...などのようなものかもしれませんね?私はすべての骨を使ってローカル変換行列を追加しますが、なぜ私のunmoveアニメーションにこれらの値が含まれているのかわかりません...

答えて

4

最終的に問題が見つかったのはUpdateBone()です。

私が問題を指摘する前に、私は一連の行列乗算を混乱させると言いたいのですが、解決策を見つけたときに、私は完全に(おそらく90%

問題は記事Matrix calculations for gpu skinningから発生します。私は答えのコードは絶対に正しいと思うし、マトリックスについてはこれ以上使うべきではないと思います。したがって、誤った使用行列は、私の外観を局所変換行列にひどく変換する。私の質問セクションの結果イメージに戻るには、glm::mat4(1.0f)を返すようにローカル変換マトリックスを変更するとバインドポーズがあります。

だから質問はなぜバインドポーズを変更するのですか?私は問題が骨空間で局所的に変形しなければならないと仮定しましたが、私は間違っています。 「

void MeshModel::UpdateBone(Bone * bone) 
{ 
    glm::mat4 parentTransform = bone->getParentTransform(); 
    if (boneName == "Scene" || boneName == "Armature") 
    { 
     bone->nodeTransform = parentTransform 
      * bone->transform // when isn't bone node, using assimp_node->mTransformation 
      * bone->localTransform; //this is your T * R matrix 
    } 
    else 
    { 
     bone->nodeTransform = parentTransform // This retrieve the transformation one level above in the tree 
      * bone->localTransform; //this is your T * R matrix 
    } 

    bone->finalTransform = globalInverse // scene->mRootNode->mTransformation 
     * bone->nodeTransform //defined above 
     * bone->inverseBindPoseMatrix; // ai_mesh->mBones[i]->mOffsetMatrix 

    for (int i = 0; i < (int)bone->children.size(); i++) { 
     UpdateBone(bone->children[i]); 
    } 
} 

私はassimp_node->mTransformationは前に私を与えるかわからない、説明のみ:私は答えを与える前に、以下のコードを見て:

void MeshModel::UpdateBone(Bone * bone) 
{ 
    glm::mat4 parentTransform = bone->getParentTransform(); 
    bone->nodeTransform = parentTransform 
     * bone->transform // assimp_node->mTransformation 
     * bone->localTransform; // T S R matrix 

    bone->finalTransform = globalInverse 
     * bone->nodeTransform 
     * bone->inverseBindPoseMatrix; // ai_mesh->mBones[i]->mOffsetMatrix 

    for (int i = 0; i < (int)bone->children.size(); i++) { 
     UpdateBone(bone->children[i]); 
    } 
} 

そして、私は以下のように変更を加えますassimpのドキュメントでは、ノードの親に対する相対的な変換です。いくつかのテストでは、mTransformationが、現在のノードを親ノードとするバインドポーズ行列であることを発見しました。私は頭骨の上にマトリックスを捕らえた写真を撮ってみましょう。

Prove

左側の部分がassimp_node->mTransformation【選択右の部分からフェッチされているtransformである私のunmoveアニメーションのnodeAnim->mPositionKeysnodeAnim->mRotationKeysnodeAnim->mScalingKeysから鍵によって計算されlocalTransform

私がやったことを振り返る、私は私の質問セクションの画像は、

最後に

、私は私が前にやったことを示してみましょう:)だけで別々のではなく、スパゲティを見て、二回形質転換のバインドポーズを作りましたアニメーションのテストを行い、アニメーション結果を修正します。

Result

(私の考え方が間違っている場合、誰ものために、私を指摘してください!Thxをする。)

関連する問題