简体   繁体   English

颈部异常---骨骼动画

[英]neck is abnormal---skeletal animation

library:assimp;model:*.fbx库:assimp;模型:*.fbx

the skeletal animation can be played normally.骨骼动画可以正常播放。 But the character's neck is stretched and does not move.但是角色的脖子被拉长了,不动。

use renderdoc to find that the vertices of the input vertex shader are no problem.使用renderdoc发现输入顶点着色器的顶点没有问题。 But the output vertex shows that the neck is abnormal.但是输出顶点显示颈部异常。 i still can't tell where the problem is我还是不知道问题出在哪里

the character's head can't move and the neck is stretched.角色的头部不能移动,颈部被拉伸。 i want to know where exactly is wrong?我想知道到底哪里错了? What goes wrong can make the head unable to move?出了什么问题会使头部无法移动?

this is the result when the error occurred:这是发生错误时的结果: https://s3.bmp.ovh/imgs/2021/10/83670b9a8898639f.png

pass the input to the shader将输入传递给着色器

for (size_t i = 0; i < MAX_BONES; ++i){
    g_Bones.bones[i] = glm::mat4(1.0f);//为了让没有骨头的模型正常显示
}
for (int32_t i = 0; i < g_Model->meshes.size(); ++i) {
    DVKMesh* mesh = g_Model->meshes[i];
    g_Position.model = mesh->linkNode->GetGlobalMatrix();
    for (int32_t j = 0; j < mesh->bones.size(); j++) {
        DVKBone* bone = g_Model->bones[mesh->bones[j]]; 
        g_Bones.bones[j] = bone->finalTransform;
        g_Bones.bones[j] = glm::inverse(mesh->linkNode->GetGlobalMatrix()) * g_Bones.bones[j];
    }
    if (mesh->bones.empty()) {
        g_Bones.bones[mesh->bones.size()] = glm::mat4(1.0f);
    }
    bufferData(g_VulkanBasic.device, sizeof(Position_UBO), &g_Position, g_PositionBuffer.memory, i * g_MinUniformBufferOffset);
}
bufferData(g_VulkanBasic.device, sizeof(BonesTransformBlock), g_Bones.bones, g_BonesBuffer.memory);

load bones and load skin加载骨骼和加载皮肤

void FillMatrixWithAiMatrix(glm::mat4& matrix, const aiMatrix4x4& aiMatrix) {
    matrix[0][0] = aiMatrix.a1;
    matrix[0][1] = aiMatrix.a2;
    matrix[0][2] = aiMatrix.a3;
    matrix[0][3] = aiMatrix.a4;
    matrix[1][0] = aiMatrix.b1;
    matrix[1][1] = aiMatrix.b2;
    matrix[1][2] = aiMatrix.b3;
    matrix[1][3] = aiMatrix.b4;
    matrix[2][0] = aiMatrix.c1;
    matrix[2][1] = aiMatrix.c2;
    matrix[2][2] = aiMatrix.c3;
    matrix[2][3] = aiMatrix.c4;
    matrix[3][0] = aiMatrix.d1;
    matrix[3][1] = aiMatrix.d2;
    matrix[3][2] = aiMatrix.d3;
    matrix[3][3] = aiMatrix.d4;
    matrix = glm::transpose(matrix);
}
void DVKModel::LoadBones(const aiScene* aiScene){
    std::unordered_map<std::string, int32_t> boneIndexMap;
    for (int32_t i = 0; i < (int32_t)aiScene->mNumMeshes; ++i){
        aiMesh* aimesh = aiScene->mMeshes[i];
        for (int32_t j = 0; j < (int32_t)aimesh->mNumBones; ++j){
            aiBone* aibone = aimesh->mBones[j];
            std::string name = aibone->mName.C_Str();
            auto it = boneIndexMap.find(name);
            if (it == boneIndexMap.end()){
                // new bone
                int32_t index = (int32_t)bones.size();
                DVKBone* bone = new DVKBone();
                bone->index = index;
                bone->parent = -1;
                bone->name = name;
                FillMatrixWithAiMatrix(bone->inverseBindPose, aibone->mOffsetMatrix);
                bones.push_back(bone);
                bonesMap.insert(std::make_pair(name, bone));
                boneIndexMap.insert(std::make_pair(name, index));
            }
        }
    }
}
void DVKModel::LoadSkin(std::unordered_map<uint32_t, DVKVertexSkin>& skinInfoMap, DVKMesh* mesh, const aiMesh* aiMesh, const aiScene* aiScene){
    std::unordered_map<int32_t, int32_t> boneIndexMap;
    for (int32_t i = 0; i < (int32_t)aiMesh->mNumBones; ++i){
        aiBone* boneInfo = aiMesh->mBones[i];
        std::string boneName(boneInfo->mName.C_Str());
        int32_t boneIndex = bonesMap[boneName]->index;
        // bone在mesh中的索引
        int32_t meshBoneIndex = 0;
        auto it = boneIndexMap.find(boneIndex);
        if (it == boneIndexMap.end()){
            meshBoneIndex = (int32_t)mesh->bones.size();
            mesh->bones.push_back(boneIndex);
            boneIndexMap.insert(std::make_pair(boneIndex, meshBoneIndex));
        }
        else{
            meshBoneIndex = it->second;
        }
        for (uint32_t j = 0; j < boneInfo->mNumWeights; ++j){
            uint32_t vertexID = boneInfo->mWeights[j].mVertexId;
            float  weight = boneInfo->mWeights[j].mWeight;
            // 顶点->Bone
            if (skinInfoMap.find(vertexID) == skinInfoMap.end()){
                skinInfoMap.insert(std::make_pair(vertexID, DVKVertexSkin()));
            }
            DVKVertexSkin* info = &(skinInfoMap[vertexID]);
            info->indices[info->used] = meshBoneIndex;
            info->weights[info->used] = weight;
            ++info->used;
            if (info->used >= 4){
                break;
            }
        }
    }
    for (auto it = skinInfoMap.begin(); it != skinInfoMap.end(); ++it){
        DVKVertexSkin& info = it->second;
        for (int32_t i = info.used; i < 4; ++i){
            info.indices[i] = 0;
            info.weights[i] = 0.0f;
        }
    }
    mesh->isSkin = true;
}

glsl vertex shader: glsl 顶点着色器:

#version 450
#extension GL_ARB_separate_shader_objects : enable
layout (location = 0) in vec3  inPosition;
layout (location = 1) in vec2  inUV0;
layout (location = 2) in vec3  inNormal;
layout (location = 3) in vec4  inSkinIndex;
layout (location = 4) in vec4  inSkinWeight;
layout (binding = 0) uniform MVPBlock {
    mat4 modelMatrix;
    mat4 viewMatrix;
    mat4 projectionMatrix;
} uboMVP;
#define MAX_BONES 64
layout (binding = 1) uniform BonesTransformBlock{
    mat4 bones[MAX_BONES];
} bonesData;
layout (location = 0) out vec2 outUV;
layout (location = 1) out vec3 outNormal;
layout (location = 2) out vec4 outColor;
void main() {
    mat4 boneMatrix = bonesData.bones[int(inSkinIndex.x)] * inSkinWeight.x;
    boneMatrix += bonesData.bones[int(inSkinIndex.y)] * inSkinWeight.y;
    boneMatrix += bonesData.bones[int(inSkinIndex.z)] * inSkinWeight.z;
    boneMatrix += bonesData.bones[int(inSkinIndex.w)] * inSkinWeight.w;
    mat4 modeMatrix   = uboMVP.modelMatrix * boneMatrix;
    mat3 normalMatrix = transpose(inverse(mat3(modeMatrix)));
    vec3 normal = normalize(normalMatrix * inNormal.xyz);

    outUV       = inUV0;
    outNormal   = normal;
    outColor    = inSkinWeight;
    
    gl_Position = uboMVP.projectionMatrix * uboMVP.viewMatrix * modeMatrix * vec4(inPosition.xyz, 1.0);
}

this is all the code: dvkmodel.h这是全部代码: dvkmodel.h

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/quaternion.hpp>

#include "vulkanFrame.h"

#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
struct DVKVertex {
    glm::vec3 pos;
    glm::vec2 uvs;
    glm::vec3 normals;
    glm::vec4 boneIDs;
    glm::vec4 weights;
    static VkVertexInputBindingDescription GetInputBinding(){
        VkVertexInputBindingDescription vertexInputBinding = {};
        vertexInputBinding.binding = 0;
        vertexInputBinding.stride = sizeof(DVKVertex);
        vertexInputBinding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
        return vertexInputBinding;
    }
    static std::vector<VkVertexInputAttributeDescription>GetInputAttributes(){
        VkFormat format[] = { VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT, VK_FORMAT_R32G32B32A32_SFLOAT };
        uint32_t offset[] = { offsetof(DVKVertex, pos), offsetof(DVKVertex, uvs), offsetof(DVKVertex, normals), offsetof(DVKVertex, boneIDs), offsetof(DVKVertex, weights) };
        std::vector<VkVertexInputAttributeDescription> vertexInputAttributs(sizeof(format) / sizeof(VkFormat));
        for (size_t i = 0; i < vertexInputAttributs.size(); ++i) {
            vertexInputAttributs[i].binding = 0;
            vertexInputAttributs[i].location = i;
            vertexInputAttributs[i].format = format[i];
            vertexInputAttributs[i].offset = offset[i];
        }
        return vertexInputAttributs;
    }
};
struct DVKBoundingBox {
    glm::vec3 min;
    glm::vec3 max;
    glm::vec3 corners[8];
    DVKBoundingBox(){

    }
    DVKBoundingBox{

    }
};

struct DVKPrimitive{
    BufferInfo indexBuffer;
    BufferInfo vertexBuffer;
    std::vector<DVKVertex>vertices;
    std::vector<uint32_t> indices;
    int32_t               vertexCount = 0;
    int32_t               triangleNum = 0;
    DVKPrimitive(){
    }
    ~DVKPrimitive(){
    }
    void DrawOnly(VkCommandBuffer cmdBuffer){
        if (vertexBuffer.size){
            vkCmdDraw(cmdBuffer, vertices.size(), 1, 0, 0);
        }
        else{
            vkCmdDrawIndexed(cmdBuffer, vertices.size(), 1, 0, 0, 0);
        }
    }
    void BindOnly(VkCommandBuffer cmdBuffer){
        VkDeviceSize offset = 0;
        if (vertexBuffer.size){
            vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer.buffer, &offset);
        }
        if (indexBuffer.size){
            vkCmdBindIndexBuffer(cmdBuffer, indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32);
        }
    }
    void BindDrawCmd(VkCommandBuffer cmdBuffer){
        BindOnly(cmdBuffer);
        DrawOnly(cmdBuffer);
    }
};

struct DVKMaterialInfo{
    std::string     diffuse;
    std::string     normalmap;
    std::string     specular;
};
struct DVKBone{
    std::string     name;
    int32_t         index = -1;
    int32_t         parent = -1;
    glm::mat4       inverseBindPose;
    glm::mat4       finalTransform;
};
struct DVKVertexSkin{
    int32_t     used = 0;
    int32_t     indices[4];
    glm::vec4   weights;
};
template <class ValueType>
struct DVKAnimChannel{
    std::vector<float>     keys;
    std::vector<ValueType> values;

    void GetValue(float key, ValueType& outPrevValue, ValueType& outNextValue, float& outAlpha){
        outAlpha = 0.0f;
        if (keys.size() == 0){
            return;
        }
        if (key <= keys.front()){
            outPrevValue = values.front();
            outNextValue = values.front();
            outAlpha = 0.0f;
            return;
        }
        if (key >= keys.back()){
            outPrevValue = values.back();
            outNextValue = values.back();
            outAlpha = 0.0f;
            return;
        }
        int32_t frameIndex = 0;
        for (int32_t i = 0; i < keys.size() - 1; ++i){
            if (key <= keys[i + 1]){
                frameIndex = i;
                break;
            }
        }
        outPrevValue = values[frameIndex + 0];
        outNextValue = values[frameIndex + 1];

        float prevKey = keys[frameIndex + 0];
        float nextKey = keys[frameIndex + 1];
        outAlpha = (key - prevKey) / (nextKey - prevKey);
    }
};
struct DVKAnimationClip {
    std::string                 nodeName;
    float                       duration;
    DVKAnimChannel<glm::vec3>   positions;
    DVKAnimChannel<glm::vec3>   scales;
    DVKAnimChannel<glm::quat>   rotations;
};
struct DVKAnimation{
    std::string name;
    float       time = 0.0f;
    float       duration = 0.0f;
    float       speed = 1.0f;
    std::unordered_map<std::string, DVKAnimationClip> clips;
};

struct DVKMesh{
    typedef std::vector<DVKPrimitive*> DVKPrimitives;
    DVKPrimitives       primitives;
    DVKBoundingBox      bounding;
    DVKNode* linkNode;
    std::vector<int32_t>bones;
    bool                isSkin = false;
    DVKMaterialInfo     material;
    int32_t             vertexCount;
    int32_t             triangleCount;

    DVKMesh()
        : linkNode(nullptr)
        , vertexCount(0)
        , triangleCount(0){

    }
    void BindOnly(VkCommandBuffer cmdBuffer){
        for (int i = 0; i < primitives.size(); ++i){
            primitives[i]->BindOnly(cmdBuffer);
        }
    }
    void DrawOnly(VkCommandBuffer cmdBuffer){
        for (int i = 0; i < primitives.size(); ++i){
            primitives[i]->DrawOnly(cmdBuffer);
        }
    }
    void BindDrawCmd(VkCommandBuffer cmdBuffer){
        for (int i = 0; i < primitives.size(); ++i){
            primitives[i]->BindDrawCmd(cmdBuffer);
        }
    }
    ~DVKMesh(){
        for (int i = 0; i < primitives.size(); ++i){
            delete primitives[i];
        }
        primitives.clear();
        linkNode = nullptr;
    }
};
struct DVKNode{
    std::string                 name;
    std::vector<DVKMesh*>       meshes;
    DVKNode* parent;
    std::vector<DVKNode*>       children;
    glm::mat4                   localMatrix;
    glm::mat4                   globalMatrix;
    DVKNode()
        : name("None")
        , parent(nullptr){
    }
    const glm::mat4& GetLocalMatrix() {
        return localMatrix;
    }
    glm::mat4& GetGlobalMatrix() {
        globalMatrix = localMatrix;
        if (parent) {
            //globalMatrix.Append(parent->GetGlobalMatrix());
            globalMatrix = parent->GetGlobalMatrix() * globalMatrix;
        }
        return globalMatrix;
    }
    void CalcBounds(DVKBoundingBox& outBounds) {
        if (meshes.size() > 0) {
            const glm::mat4& matrix = GetGlobalMatrix();
            for (int32_t i = 0; i < meshes.size(); ++i) {
                glm::vec3 mmin = matrix * glm::vec4(meshes[i]->bounding.min, 1.0f);
                glm::vec3 mmax = matrix * glm::vec4(meshes[i]->bounding.max, 1.0f);
                outBounds.min = glm::min(outBounds.min, mmin);
                outBounds.min = glm::min(outBounds.min, mmax);
                outBounds.max = glm::max(outBounds.max, mmin);
                outBounds.max = glm::max(outBounds.max, mmax);
            }
        }
        for (int32_t i = 0; i < children.size(); ++i) {
            children[i]->CalcBounds(outBounds);
        }
    }

    DVKBoundingBox GetBounds() {
        DVKBoundingBox bounds;
        bounds.min = glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX);
        bounds.max = glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX);
        CalcBounds(bounds);
        bounds.UpdateCorners();
        return bounds;
    }
    ~DVKNode(){
        for (int32_t i = 0; i < meshes.size(); ++i){
            delete meshes[i];
        }
        meshes.clear();
        for (int32_t i = 0; i < children.size(); ++i){
            delete children[i];
        }
        children.clear();
    }
};
class DVKModel{
public:
    DVKModel()
        : device(nullptr)
        , rootNode(nullptr){

    }
    ~DVKModel(){
        delete rootNode;
        rootNode = nullptr;
        device = nullptr;
        meshes.clear();
        linearNodes.clear();
        for (int32_t i = 0; i < bones.size(); ++i){
            delete bones[i];
        }
        bones.clear();
    }
    void LoadFromFile(VkDevice device, const std::string& filename);
protected:
    DVKNode* LoadNode(const aiNode* node, const aiScene* scene);
    DVKMesh* LoadMesh(const aiMesh* mesh, const aiScene* scene);
    void LoadBones(const aiScene* aiScene);
    void LoadSkin(std::unordered_map<uint32_t, DVKVertexSkin>& skinInfoMap, DVKMesh* mesh, const aiMesh* aiMesh, const aiScene* aiScene);
    void LoadVertexDatas(std::unordered_map<uint32_t, DVKVertexSkin>& skinInfoMap, std::vector<DVKVertex>& vertices, glm::vec3& mmax, glm::vec3& mmin, DVKMesh* mesh, const aiMesh* aiMesh, const aiScene* aiScene);
    void LoadIndices(std::vector<uint32_t>& indices, const aiMesh* aiMesh, const aiScene* aiScene);

    void LoadPrimitives(std::vector<DVKVertex>& vertices, std::vector<uint32_t>& indices, DVKMesh* mesh, const aiMesh* aiMesh, const aiScene* aiScene);
    void LoadAnim(const aiScene* aiScene);

public:
    typedef std::unordered_map<std::string, DVKNode*> NodesMap;
    typedef std::unordered_map<std::string, DVKBone*> BonesMap;
    VkDevice   device;
    DVKNode* rootNode;
    std::vector<DVKNode*>           linearNodes;
    std::vector<DVKMesh*>           meshes;
    NodesMap                        nodesMap;
    std::vector<DVKBone*>           bones;
    BonesMap                        bonesMap;
    std::vector<DVKAnimation>       animations;
    int32_t                         animIndex = -1;

private:
    bool                            loadSkin = false;
};

dvkmodel.cpp dvkmodel.cpp

#include "DVKModel.h"
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <assimp/cimport.h>
void FillMatrixWithAiMatrix(glm::mat4& matrix, const aiMatrix4x4& aiMatrix) {
    matrix[0][0] = aiMatrix.a1;
    matrix[0][1] = aiMatrix.a2;
    matrix[0][2] = aiMatrix.a3;
    matrix[0][3] = aiMatrix.a4;
    matrix[1][0] = aiMatrix.b1;
    matrix[1][1] = aiMatrix.b2;
    matrix[1][2] = aiMatrix.b3;
    matrix[1][3] = aiMatrix.b4;
    matrix[2][0] = aiMatrix.c1;
    matrix[2][1] = aiMatrix.c2;
    matrix[2][2] = aiMatrix.c3;
    matrix[2][3] = aiMatrix.c4;
    matrix[3][0] = aiMatrix.d1;
    matrix[3][1] = aiMatrix.d2;
    matrix[3][2] = aiMatrix.d3;
    matrix[3][3] = aiMatrix.d4;
    matrix = glm::transpose(matrix);
}
void DVKModel::LoadFromFile(VkDevice device, const std::string& filename){
    this->device = device;
    int assimpFlags = aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenUVCoords | aiProcess_GenSmoothNormals;
    loadSkin = true;
    Assimp::Importer importer;
    const aiScene* scene = importer.ReadFile(filename, assimpFlags);
    LoadBones(scene);
    LoadNode(scene->mRootNode, scene);
    LoadAnim(scene);
}
void DVKModel::LoadBones(const aiScene* aiScene){
    std::unordered_map<std::string, int32_t> boneIndexMap;
    for (int32_t i = 0; i < (int32_t)aiScene->mNumMeshes; ++i){
        aiMesh* aimesh = aiScene->mMeshes[i];
        for (int32_t j = 0; j < (int32_t)aimesh->mNumBones; ++j){
            aiBone* aibone = aimesh->mBones[j];
            std::string name = aibone->mName.C_Str();
            auto it = boneIndexMap.find(name);
            if (it == boneIndexMap.end()){
                // new bone
                int32_t index = (int32_t)bones.size();
                DVKBone* bone = new DVKBone();
                bone->index = index;
                bone->parent = -1;
                bone->name = name;
                FillMatrixWithAiMatrix(bone->inverseBindPose, aibone->mOffsetMatrix);
                // 记录Bone信息
                bones.push_back(bone);
                bonesMap.insert(std::make_pair(name, bone));
                // cache
                boneIndexMap.insert(std::make_pair(name, index));
            }
        }
    }
}
void DVKModel::LoadSkin(std::unordered_map<uint32_t, DVKVertexSkin>& skinInfoMap, DVKMesh* mesh, const aiMesh* aiMesh, const aiScene* aiScene){
    std::unordered_map<int32_t, int32_t> boneIndexMap;
    for (int32_t i = 0; i < (int32_t)aiMesh->mNumBones; ++i){
        aiBone* boneInfo = aiMesh->mBones[i];
        std::string boneName(boneInfo->mName.C_Str());
        int32_t boneIndex = bonesMap[boneName]->index;
        // bone在mesh中的索引
        int32_t meshBoneIndex = 0;
        auto it = boneIndexMap.find(boneIndex);
        if (it == boneIndexMap.end()){
            meshBoneIndex = (int32_t)mesh->bones.size();
            mesh->bones.push_back(boneIndex);
            boneIndexMap.insert(std::make_pair(boneIndex, meshBoneIndex));
        }
        else{
            meshBoneIndex = it->second;
        }
        for (uint32_t j = 0; j < boneInfo->mNumWeights; ++j){
            uint32_t vertexID = boneInfo->mWeights[j].mVertexId;
            float  weight = boneInfo->mWeights[j].mWeight;
            if (skinInfoMap.find(vertexID) == skinInfoMap.end()){
                skinInfoMap.insert(std::make_pair(vertexID, DVKVertexSkin()));
            }
            DVKVertexSkin* info = &(skinInfoMap[vertexID]);
            info->indices[info->used] = meshBoneIndex;
            info->weights[info->used] = weight;
            ++info->used;
            if (info->used >= 4){
                break;
            }
        }
    }
    for (auto it = skinInfoMap.begin(); it != skinInfoMap.end(); ++it){
        DVKVertexSkin& info = it->second;
        for (int32_t i = info.used; i < 4; ++i){
            info.indices[i] = 0;
            info.weights[i] = 0.0f;
        }
    }

    mesh->isSkin = true;
}
void DVKModel::LoadVertexDatas(std::unordered_map<uint32_t, DVKVertexSkin>& skinInfoMap, std::vector<DVKVertex>& vertices, glm::vec3& mmax, glm::vec3& mmin, DVKMesh* mesh, const aiMesh* aiMesh, const aiScene* aiScene) {
    for (int32_t i = 0; i < (int32_t)aiMesh->mNumVertices; ++i){
        DVKVertex v;
        v.pos = glm::vec3(aiMesh->mVertices[i].x, aiMesh->mVertices[i].y, aiMesh->mVertices[i].z);
        if (aiMesh->HasTextureCoords(0))
            v.uvs = glm::vec2(aiMesh->mTextureCoords[0][i].x, aiMesh->mTextureCoords[0][i].y);
        v.normals = glm::vec3(aiMesh->mNormals[i].x, aiMesh->mNormals[i].y, aiMesh->mNormals[i].z);
        DVKVertexSkin& skin = skinInfoMap[i];
        if (mesh->isSkin) {
            v.boneIDs = glm::vec4(skin.indices[0], skin.indices[1], skin.indices[2], skin.indices[3]);//默认0
            v.weights = glm::vec4(skin.weights[0], skin.weights[1], skin.weights[2], skin.weights[3]);//默认1, 0, 0, 0
        }
        else {
            v.boneIDs = glm::vec4(.0f);
            v.weights = glm::vec4(1.0f, .0f, .0f, .0f);
        }
        vertices.push_back(v);
    }
}
void DVKModel::LoadIndices(std::vector<uint32_t>& indices, const aiMesh* aiMesh, const aiScene* aiScene){
    for (int32_t i = 0; i < (int32_t)aiMesh->mNumFaces; ++i){
        indices.push_back(aiMesh->mFaces[i].mIndices[0]);
        indices.push_back(aiMesh->mFaces[i].mIndices[1]);
        indices.push_back(aiMesh->mFaces[i].mIndices[2]);
    }
}
void DVKModel::LoadPrimitives(std::vector<DVKVertex>& vertices, std::vector<uint32_t>& indices, DVKMesh* mesh, const aiMesh* aiMesh, const aiScene* aiScene){
    std::unordered_map<uint32_t, uint32_t> indicesMap;
    DVKPrimitive* primitive = new DVKPrimitive();
    primitive->vertices = vertices;
    primitive->indices = indices;
    createBuffer(device, indices.size() * sizeof(uint32_t), VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, primitive->indexBuffer);
    bufferData(device, indices.size() * sizeof(uint32_t), indices.data(), primitive->indexBuffer.memory);
    createBuffer(device, vertices.size() * sizeof(DVKVertex), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, primitive->vertexBuffer);
    bufferData(device, vertices.size() * sizeof(DVKVertex), vertices.data(), primitive->vertexBuffer.memory);
    mesh->primitives.push_back(primitive);
}
DVKMesh* DVKModel::LoadMesh(const aiMesh* aiMesh, const aiScene* aiScene){
    DVKMesh* mesh = new DVKMesh();
    // load material
    aiMaterial* material = aiScene->mMaterials[aiMesh->mMaterialIndex];
    // load bones
    std::unordered_map<uint32_t, DVKVertexSkin> skinInfoMap;
    if (aiMesh->mNumBones > 0 && loadSkin){
        LoadSkin(skinInfoMap, mesh, aiMesh, aiScene);
    }
    // load vertex data
    std::vector<DVKVertex> vertices;
    glm::vec3 mmin(FLT_MAX, FLT_MAX, FLT_MAX);
    glm::vec3 mmax(-FLT_MAX, -FLT_MAX, -FLT_MAX);
    LoadVertexDatas(skinInfoMap, vertices, mmax, mmin, mesh, aiMesh, aiScene);
#else
    Vector3 mmin(MAX_FLT, MAX_FLT, MAX_FLT);
    Vector3 mmax(-MAX_FLT, -MAX_FLT, -MAX_FLT);
    LoadVertexDatas(skinInfoMap, vertices, mmax, mmin, mesh, aiMesh, aiScene);
    // load indices
    std::vector<uint32_t> indices;
    LoadIndices(indices, aiMesh, aiScene);
    // load primitives
    LoadPrimitives(vertices, indices, mesh, aiMesh, aiScene);
    mesh->bounding.min = mmin;
    mesh->bounding.max = mmax;
    mesh->bounding.UpdateCorners();
    return mesh;
}
DVKNode* DVKModel::LoadNode(const aiNode* aiNode, const aiScene* aiScene){
    DVKNode* vkNode = new DVKNode();
    vkNode->name = aiNode->mName.C_Str();
    if (rootNode == nullptr){
        rootNode = vkNode;
    }
    // mesh
    if (aiNode->mNumMeshes > 0){
        for (uint32_t i = 0; i < aiNode->mNumMeshes; ++i){
            DVKMesh* vkMesh = LoadMesh(aiScene->mMeshes[aiNode->mMeshes[i]], aiScene);
            vkMesh->linkNode = vkNode;
            vkNode->meshes.push_back(vkMesh);
            meshes.push_back(vkMesh);
        }
    }
    // nodes map
    nodesMap.insert(std::make_pair(vkNode->name, vkNode));
    linearNodes.push_back(vkNode);
    // bones parent
    int32_t boneParentIndex = -1;{
        auto it = bonesMap.find(vkNode->name);
        if (it != bonesMap.end()){
            boneParentIndex = it->second->index;
        }
    }
    // children node
    for (int32_t i = 0; i < (int32_t)aiNode->mNumChildren; ++i){
        DVKNode* childNode = LoadNode(aiNode->mChildren[i], aiScene);
        childNode->parent = vkNode;
        vkNode->children.push_back(childNode);

        // bones relationship
        {
            auto it = bonesMap.find(childNode->name);
            if (it != bonesMap.end()){
                it->second->parent = boneParentIndex;
            }
        }
    }
    return vkNode;
}
void DVKModel::LoadAnim(const aiScene* aiScene) {
    for (int32_t i = 0; i < (int32_t)aiScene->mNumAnimations; ++i) {
        aiAnimation* aianimation = aiScene->mAnimations[i];
        float timeTick = aianimation->mTicksPerSecond != 0 ? (float)aianimation->mTicksPerSecond : 25.0f
        animations.push_back(DVKAnimation());
        DVKAnimation& dvkAnimation = animations.back();

        for (int32_t j = 0; j < (int32_t)aianimation->mNumChannels; ++j){
            aiNodeAnim* nodeAnim = aianimation->mChannels[j];
            std::string nodeName = nodeAnim->mNodeName.C_Str();

            dvkAnimation.clips.insert(std::make_pair(nodeName, DVKAnimationClip()));

            DVKAnimationClip& animClip = dvkAnimation.clips[nodeName];
            animClip.nodeName = nodeName;
            animClip.duration = 0.0f;

            // position
            for (int32_t index = 0; index < (int32_t)nodeAnim->mNumPositionKeys; ++index){
                aiVectorKey& aikey = nodeAnim->mPositionKeys[index];
                animClip.positions.keys.push_back((float)aikey.mTime / timeTick);
                animClip.positions.values.push_back(glm::vec3(aikey.mValue.x, aikey.mValue.y, aikey.mValue.z));
                animClip.duration = glm::max((float)aikey.mTime / timeTick, animClip.duration);
            }

            // scale
            for (int32_t index = 0; index < (int32_t)nodeAnim->mNumScalingKeys; ++index){
                aiVectorKey& aikey = nodeAnim->mScalingKeys[index];
                animClip.scales.keys.push_back((float)aikey.mTime / timeTick);
                animClip.scales.values.push_back(glm::vec3(aikey.mValue.x, aikey.mValue.y, aikey.mValue.z));
                animClip.duration = glm::max((float)aikey.mTime / timeTick, animClip.duration);
            }

            // rotation
            for (int32_t index = 0; index < (int32_t)nodeAnim->mNumRotationKeys; ++index){
                aiQuatKey& aikey = nodeAnim->mRotationKeys[index];
                animClip.rotations.keys.push_back((float)aikey.mTime / timeTick);
                animClip.rotations.values.push_back(glm::quat(aikey.mValue.w, aikey.mValue.x, aikey.mValue.y, aikey.mValue.z));
                animClip.duration = glm::max((float)aikey.mTime / timeTick, animClip.duration);
            }
            dvkAnimation.duration = glm::max(animClip.duration, dvkAnimation.duration);
        }
    }
}
void AppendScale(glm::mat4& m, const glm::vec3& scale) {
    glm::mat4 matrix;
    matrix = glm::mat4(1.0f);
    matrix[0][0] = scale.x;
    matrix[1][1] = scale.y;
    matrix[2][2] = scale.z;
    m = matrix * m;
}
void DVKModel::GotoAnimation(float time) {
    if (animIndex == -1) {
        return;
    }
    DVKAnimation& animation = animations[animIndex];
    animation.time = glm::clamp(time, 0.0f, animation.duration);
    // update nodes animation
    for (auto it = animation.clips.begin(); it != animation.clips.end(); ++it){
        DVKAnimationClip& clip = it->second;
        DVKNode* node = nodesMap[clip.nodeName];

        float alpha = 0.0f;
        // rotation
        glm::quat prevRot(1, 0, 0, 0);
        glm::quat nextRot(1, 0, 0, 0);
        clip.rotations.GetValue(animation.time, prevRot, nextRot, alpha);
        glm::quat retRot = glm::lerp(prevRot, nextRot, alpha);

        // position
        glm::vec3 prevPos(0, 0, 0);
        glm::vec3 nextPos(0, 0, 0);
        clip.positions.GetValue(animation.time, prevPos, nextPos, alpha);
        glm::vec3 retPos = prevPos + alpha * (nextPos - prevPos);//MMath::Lerp(prevPos, nextPos, alpha);

        // scale
        glm::vec3 prevScale(1, 1, 1);
        glm::vec3 nextScale(1, 1, 1);
        clip.scales.GetValue(animation.time, prevScale, nextScale, alpha);
        glm::vec3 retScale = prevScale + alpha * (nextScale - prevScale);
        node->localMatrix = glm::mat4(1.0f);
        AppendScale(node->localMatrix, retScale);
        node->localMatrix *= glm::mat4_cast(retRot);
        node->localMatrix[3][0] += retPos.x;
        node->localMatrix[3][1] += retPos.y;
        node->localMatrix[3][2] += retPos.z;
    }
    // update bones
    for (int32_t i = 0; i < bones.size(); ++i){
        DVKBone* bone = bones[i];
        DVKNode* node = nodesMap[bone->name];
        // 注意行列矩阵的区别
        bone->finalTransform = bone->inverseBindPose;
        bone->finalTransform = node->GetGlobalMatrix() * bone->finalTransform;
    }
}

I haven't looked through your code in detail, but from skimming over it, it appears that you aren't using aiNode::mTransformation which you have to in order to get the correct transformation wrt a bone's parent bone.我没有详细查看您的代码,但是从略读它的角度来看,您似乎没有使用aiNode::mTransformation ,为了获得骨骼的父骨骼的正确转换,您必须使用aiNode::mTransformation ASSIMP's documentation describes this parameter like follows: ASSIMP 的文档对这个参数的描述如下:

    /** The transformation relative to the node's parent. */
    C_STRUCT aiMatrix4x4 mTransformation;

And care must be taken when converting ASSIMP's matrices (which are row-major) to matrices that are typically used with OpenGL or Vulkan (which are typically column-major).将 ASSIMP 的矩阵(行优先)转换为通常与 OpenGL 或 Vulkan 一起使用的矩阵(通常是列优先)时必须小心。 The following code does the necessary transformation in this case:在这种情况下,以下代码执行必要的转换:

/** Convert from a row-major ASSIMP matrix to a column-major GLM matrix */
glm::mat4 to_mat4(const aiMatrix4x4& aAssimpMat)
{
    return glm::transpose(*reinterpret_cast<const glm::mat4*>(&aAssimpMat[0][0]));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM