2016-09-22 14 views
6

Gần đây tôi đang làm việc về nhập hình động xương, vì vậy tôi đã tạo mô hình 3D giống như minecraft với một số kỹ thuật IK để kiểm tra nhập hoạt ảnh Assimp. Định dạng Ouput là COLLADA (*. Dae), và công cụ tôi sử dụng là Blender. Về phía lập trình, môi trường của tôi là opengl/glm/assimp. Tôi nghĩ rằng những thông tin cho vấn đề của tôi là đủ. Một điều, các hình ảnh động của mô hình, tôi chỉ ghi 7 unmove keyframe để thử nghiệm hoạt hình assimp.Biến đổi xương hoạt hình Assimp

Đầu tiên, tôi đoán chuyển đổi của tôi ngoại trừ phần biến đổi cục bộ là chính xác, vì vậy hãy để hàm chỉ trả về glm::mat4(1.0f) và kết quả cho thấy mô hình ràng buộc (không chắc chắn). (xem hình bên dưới)

Thứ hai, Xoay lại giá trị glm::mat4(1.0f) thành bone->localTransform = transform * scaling * glm::mat4(1.0f);, sau đó là biến dạng của mô hình. (Xem bên dưới hình ảnh)

hình ảnh thử nghiệm và mô hình trong máy xay sinh tố: test and origin (bone->localTransform = glm::mat4(1.0f) * scaling * rotate;: hình ảnh này là dưới mặt đất :()

Mã ở đây:

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

Ý tưởng đang tham chiếu từ Matrix calculations for gpu skinningSkeletal Animation With Assimp.

Nói chung, tôi cắt bỏ tất cả thông tin từ assimp thành MeshModel và lưu nó vào cấu trúc xương, vì vậy tôi nghĩ rằng thông tin là ổn chứ?

Điều cuối cùng, đỉnh đang đổ bóng của tôi:

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

Nếu câu hỏi của tôi ở trên, thiếu mã hoặc mô tả mơ hồ, xin vui lòng cho tôi biết, Cảm ơn bạn!

Edit: (1)

Thêm vào đó, thông tin bởi xương tôi như thế này (mã lấy một phần):

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

đã có một số vector chuyển đổi, do đó, mã của tôi ở trên glm::mat4 transform = GetInterpolateTransform(time, bone->transformKeys);, Absloutely, nhận số cùng giá trị từ nó. Tôi không chắc chắn tôi đã thực hiện một hình ảnh động keyframe nomove cung cấp các giá trị biến đổi là đúng hay không (tất nhiên nó có 7 khung hình chính).

Nội dung khung chính như thế này (gỡ lỗi trên xương đầu): keyframe from head 7 khung hình chính khác, cùng giá trị vector.

Edit: (2)

Nếu bạn muốn kiểm tra tập tin dae của tôi, tôi đặt nó trong jsfiddle, đến và mang nó :). Một điều nữa, trong Unity tệp của tôi hoạt động chính xác, vì vậy tôi nghĩ có lẽ không phải biến đổi cục bộ của tôi xảy ra vấn đề, có vẻ như vấn đề có thể là một số khác như parentTransform hoặc bone-> transform ... etc? Tôi cũng thêm ma trận biến đổi cục bộ với tất cả xương, Nhưng không thể tìm ra lý do tại sao COLLADA chứa các giá trị này cho hoạt ảnh chưa được mở của tôi ...

Trả lời

4

Đối với số lượng thử nghiệm và cuối cùng phát hiện sự cố là phần UpdateBone().

Trước khi tôi chỉ ra vấn đề của mình, tôi cần nói chuỗi phép nhân ma trận cho phép tôi nhầm lẫn, nhưng khi tôi tìm ra giải pháp, nó chỉ làm cho tôi hoàn toàn (có thể chỉ 90%) nhận ra tất cả ma trận đang làm.

Sự cố xuất phát từ bài viết, Matrix calculations for gpu skinning. Tôi cho rằng mã câu trả lời là hoàn toàn đúng và không nghĩ gì thêm về ma trận nên được sử dụng. Vì vậy, lạm dụng ma trận khủng khiếp chuyển giao của tôi vào ma trận biến đổi cục bộ. Quay lại hình ảnh kết quả trong phần câu hỏi của tôi là ràng buộc đặt ra khi tôi thay đổi ma trận biến đổi cục bộ để trả về glm::mat4(1.0f).

Vì vậy, câu hỏi đặt ra là tại sao thay đổi đặt ra ràng buộc? Tôi cho rằng vấn đề phải là biến đổi cục bộ trong không gian xương, nhưng tôi sai. Trước khi tôi đưa ra câu trả lời, hãy nhìn vào mã bên dưới:

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

Và tôi thực hiện thay đổi như sau:

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

Tôi không biết những gì assimp_node->mTransformation cho tôi trước đó, chỉ mô tả " Việc chuyển đổi liên quan đến cha mẹ của nút "trong tài liệu assimp. Đối với một số thử nghiệm, tôi thấy rằng mTransformation là ma trận đặt ra ràng buộc mà nút hiện tại liên quan đến cha mẹ nếu tôi sử dụng chúng trên nút xương. Hãy để tôi đưa ra một bức ảnh chụp ma trận trên xương đầu.

Prove

Phần bên trái là transform mà được lấy từ assimp_node->mTransformation .Công phần bên phải là của tôi unmove hoạt hình của localTransform được tính bằng các phím từ nodeAnim->mPositionKeys, nodeAnim->mRotationKeysnodeAnim->mScalingKeys.

Nhìn lại những gì tôi đã làm, tôi làm một ràng buộc gây tranformation hai lần, vì vậy hình ảnh trong phần câu hỏi của tôi trông mì spaghetti chỉ riêng biệt nhưng không :)

Trên cuối cùng, chúng ta hãy để tôi chỉ cho những gì tôi đã làm trước kiểm tra hoạt ảnh chưa xác định và kết quả hoạt ảnh chính xác.

Result

(Đối với tất cả mọi người, Nếu khái niệm của tôi là sai, xin vui lòng chỉ cho tôi ra! Thx.)

Các vấn đề liên quan