LeeMcQueen / GameDemo

Demo
0 stars 0 forks source link

【add】 AnimaLoader #10

Closed LeeMcQueen closed 3 years ago

LeeMcQueen commented 3 years ago

//使用Assimp通过文件名得到Scene void AnimaLoader::loadAssimpScene(const char *filePath) {

Assimp::Importer impoerter
const aiScene *scene = importer.ReadFile(filePath, aiProcess_Triangulate | aiProcess_FileUVs | aiProcess_GenSmoothNormals);
if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode){
    std::cout << "ERROR::Assimp :" << importer.GetErrorString() << std::endl;
}
    mesh = scene->mMeshes[0];

}

RawModel AnimaLoader::loadAnimaModel(const aiScene scene, aiMesh mesh, std::vector& verticseOutput、std::vector& indicesp\Output, Bone& skeletonOutput,unsigned int& nBoneCount) {

verticesOutput = {};
indicesOutput = {};

/加载顶点,法线,uv坐标
for (unsigned int i = 0; i < mesh->mNumVertices; i++) {

    //取得模型坐标用变量
    Vertex vertex;
    //空的顶点
    glm::vec3 vector;

    //取得顶点
    vector.x = mesh->mVertices[i].x;
    vector.y = mesh->mVertices[i].y;
    vector.z = mesh->mVertices[i].z;
    vertex.setPosition(vector);

    vector.x = mesh->mNormals[i].x;
    vector.y = mesh->mNormals[i].y;
    vector.z = mesh->mNormals[i].z;
    vertex.setNormal(vector);

    glm::vec2 vec;

    //注意这里就只有一个纹理,需要的话需要动态设定
    vec.x = mesh->mTextureCoords[0][i].x;
    vec.y = mesh->mTextureCoords[0][i].y;
    vertex.setTexture(vec);

    //初始化骨骼ID
    vertex.setBoneIds(glm::ivec4(0));
    vertex.setBoneWeights(glm::vec4(0.0f));

    verticesOutput.push_back(vertex);
}

//加载骨骼数据到顶点数组
//boneInfo的结构是 谷歌名<string> 矩阵pair
std::unordered_map<std::string, std::pair<int, glm::mat4>> boneInfo = {};
std::vector<unsigned int> boneCounts;
//verticesOutput数据相同长度的boneCounts数据内容都是0
boneCounts.resize(verticesOutput.size(), 0);
//得到模型的总骨骼数
nBoneCount = mesh->mNumBones;

//循环骨骼数量得到???
for (unsigned int i = 0; i < nBoneCount; i++) {
    //得到每个骨头
    aiBone *bone = mesh->mBones[i];
    //从Assimp格式转换成glm
    glm::mat4 matrix = assimpToGlmMatrix(bone->mOffsetMatrix);
    //按照骨骼名称(string形式)往里面注入map, map的形式是(i, matrix)
    boneInfo[bone->mName.C_Str()] = { i, matrix };

    //循环骨骼里面的顶点(通过总权重数就知道有多少个顶点)
    for (unsigned int j = 0; j < bone->mNumWeights; j++) {
        //当前骨骼的顶点ID
        unsigned int id = bone->mWeights[j].mVertexId;
        //当前骨骼的顶点的权重值
        float weight = bone->mWeights[j].mWeight;
        boneCounts[id]++;

        //根据
        switch (boneCounts[id])
        {
        case 1:
            verticesOutput[id].setBoneIds_x(i);
            verticesOutput[id].setBoneWeights_x(weight);
            break;
        case 2:
            verticesOutput[id].setBoneIds_y(i);
            verticesOutput[id].setBoneWeights_y(weight);
            break;
        case 3:
            verticesOutput[id].setBoneIds_z(i);
            verticesOutput[id].setBoneWeights_z(weight);
            break;
        case 4:
            verticesOutput[id].setBoneIds_w(i);
            verticesOutput[id].setBoneWeights_w(weight);
            break;

        default:
            break;
        }
    }
}

//让所有权重的和为1
for (unsigned int i = 0; i < verticesOutput.size(); i++) {
    //取得所有顶点数组里面的骨骼权重
    glm::vec4 &boneWeight = verticesOutput[i].getBoneWieghts();

    float totalWeight = boneWeight.x + boneWeight.y + boneWeight.z + boneWeight.w;
    if (totalWeight > 0.0f) {
        verticesOutput[i].setBoneWeights(glm::vec4(
            boneWeight.x / totalWeight,
            boneWeight.y / totalWeight,
            boneWeight.z / totalWeight,
            boneWeight.w / totalWeight)
        );
    }
}

for (unsigned int i = 0; i < mesh->mNumFaces; i++) {
    aiFace &face = mesh->mFaces[i];
    for (unsigned int j = 0; j < face.mNumIndices; j++) {
        indicesOutput.push_back(face.mIndices[j]);
    }
}
//
readSkeleton(skeletonOutput, scene->mRootNode, boneInfo);

//实例化Vao加载功能
Loader loader;
return loader.createVertexArray(std::vector<Vertex>& vertices, std::vector<unsigned int> indices);

}

bool readSkeleton(Bone &boneOutput, aiNode *node, std::unordered_map<std::string, std::pair<int, glm::mat4>> &boneInfoTable) {

if (boneInfoTable.find(node->mName.C_Str()) != boneInfoTable.end()) {
    boneOutput.setName(node->mName.C_Str());
    boneOutput.setId(boneInfoTable[boneOutput.getName()].first);
    boneOutput.setOffset(boneInfoTable[boneOutput.getName()].second);

    for (int i = 0; i < node->mNumChildren; i++) {
        Bone child;
        readSkeleton(child, node->mChildren[i], boneInfoTable);
        //boneOutput.children.push_back(child);
        boneOutput.children_.push_back(child);
    }
    return true;
}
else {
    for (int i = 0; i < node->mNumChildren; i++) {
        if (readSkeleton(boneOutput, node->mChildren[i], boneInfoTable)) {
            return true;
        }
    }
}
return false;

}