#ifndefMesh_H#defineMesh_H#include"Component.h"#include<glm/glm.hpp>#include<glm/gtc/matrix_transform.hpp>#include<string>#include<vector>#include<map>#include"Texture.h"#include"Shader.h"#defineMAX_BONE_INFLUENCE4usingnamespace std;structVertex{
glm::vec3 Position;// normal
glm::vec3 Normal;// texCoords
glm::vec2 TexCoords;// tangent
glm::vec3 Tangent;// bitangent
glm::vec3 Bitangent;//bone indexes which will influence this vertexint m_BoneIDs[MAX_BONE_INFLUENCE];weights from each bonefloat m_Weights[MAX_BONE_INFLUENCE];};structBoneInfo{
glm::mat4 FinalTransformation;// Final transformation to apply to vertices
glm::mat4 BoneOffset;// Initial offset from local to bone space. BoneInfo(){
BoneOffset = glm::mat4(1.0f);
FinalTransformation = glm::mat4(1.0f);}voidSetBoneOffset(glm::mat4 a){
if(BoneOffset == glm::mat4(1.0f))
BoneOffset = a;}};structTexture{
Texture2D* texture2D;
string type;
string path;bool haveData;};structVertexBoneData{
unsignedint IDs[4];//!< An array of 4 bone Ids that influence a single vertex.float Weights[4];//!< An array of the weight influence per bone. VertexBoneData(){
// 0's out the arrays. Reset();}voidReset(){
memset(IDs,0,4*sizeof(IDs[0]));memset(Weights,0,4*sizeof(Weights[0]));}voidAddBoneData(unsignedint BoneID,float Weight){
for(unsignedint i =0; i <4; i++){
// Check to see if there are any empty weight values. if(Weights[i]==0.0){
// Add ID of bone.
IDs[i]= BoneID;// Set the vertex weight influence for this bone ID.
Weights[i]= Weight;return;}}// should never get here - more bones than we have space forassert(0);}};classMesh{
public:/* 网格数据 */
vector<Vertex> vertices;
vector<unsignedint> indices;
vector<Texture> textures;unsignedint VAO;unsignedint BaseVertex;/* 函数 */Mesh(vector<Vertex> vertices, vector<unsignedint> indices, vector<Texture> textures,int offset, std::vector<VertexBoneData> bones, map<unsignedint, glm::mat4> boneOffsets);voidsetupMesh(vector<VertexBoneData>& Bones);voidDraw(Shader& shader);private:/* 渲染数据 */unsignedint VBO, EBO, boneBo;
map<unsignedint, glm::mat4> m_boneOffsets;/* 函数 */};#endif--------------------------#include"Mesh.h"Mesh::Mesh(vector<Vertex> vertices, vector<unsignedint> indices, vector<Texture> textures,int offset, std::vector<VertexBoneData> bones ,Shader *shader){
this->vertices = vertices;this->indices = indices;this->textures = textures;
BaseVertex = offset;
m_pShaderProg = shader;setupMesh(bones);}voidMesh::setupMesh(vector<VertexBoneData>& Bones){
glGenVertexArrays(1,&VAO);glGenBuffers(1,&VBO);glBindBuffer(GL_ARRAY_BUFFER, VBO);glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vertex),&vertices[0], GL_STATIC_DRAW);glBindBuffer(GL_ARRAY_BUFFER,0);glGenBuffers(1,&boneBo);glBindBuffer(GL_ARRAY_BUFFER, boneBo);glBufferData(GL_ARRAY_BUFFER,sizeof(Bones[0])* vertices.size(),&Bones[BaseVertex], GL_STATIC_DRAW);glBindBuffer(GL_ARRAY_BUFFER,0);glBindVertexArray(VAO);// load data into vertex buffers//glBindBuffer(GL_ARRAY_BUFFER, VBO);// A great thing about structs is that their memory layout is sequential for all its items.// The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2 array which// again translates to 3/2 floats which translates to a byte array./*glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);*/// set the vertex attribute pointers// vertex PositionsglBindBuffer(GL_ARRAY_BUFFER, VBO);glEnableVertexAttribArray(0);glVertexAttribPointer(0,3, GL_FLOAT, GL_FALSE,sizeof(Vertex),(void*)0);// vertex normalsglEnableVertexAttribArray(1);glVertexAttribPointer(1,3, GL_FLOAT, GL_FALSE,sizeof(Vertex),(void*)offsetof(Vertex, Normal));// vertex texture coordsglEnableVertexAttribArray(2);glVertexAttribPointer(2,2, GL_FLOAT, GL_FALSE,sizeof(Vertex),(void*)offsetof(Vertex, TexCoords));// vertex tangentglEnableVertexAttribArray(3);glVertexAttribPointer(3,3, GL_FLOAT, GL_FALSE,sizeof(Vertex),(void*)offsetof(Vertex, Tangent));// vertex bitangentglEnableVertexAttribArray(4);glVertexAttribPointer(4,3, GL_FLOAT, GL_FALSE,sizeof(Vertex),(void*)offsetof(Vertex, Bitangent));glBindBuffer(GL_ARRAY_BUFFER,0);glBindBuffer(GL_ARRAY_BUFFER, boneBo);/*glBindBuffer(GL_ARRAY_BUFFER, boneBo); glBufferData(GL_ARRAY_BUFFER, sizeof(VertexBoneData) * Bones.size(), &Bones[0], GL_STATIC_DRAW);*/glEnableVertexAttribArray(5);glVertexAttribIPointer(5,4, GL_INT,sizeof(VertexBoneData),(constvoid*)0);glEnableVertexAttribArray(6);glVertexAttribPointer(6,4, GL_FLOAT, GL_FALSE,sizeof(VertexBoneData),(constvoid*)16);glBindBuffer(GL_ARRAY_BUFFER,0);// ids//glEnableVertexAttribArray(5);//glVertexAttribIPointer(5, 4, GL_INT, sizeof(Vertex), (void*)offsetof(Vertex, m_BoneIDs)); weights//glEnableVertexAttribArray(6);//glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, m_Weights));glGenBuffers(1,&EBO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(indices[0]),&indices[0], GL_STATIC_DRAW);glBindBuffer(GL_ARRAY_BUFFER,0);glBindVertexArray(0);}voidMesh::Draw(Shader& shader){
/*auto iter = m_boneOffsets.begin(); while (iter != m_boneOffsets.end()) { glm::mat4 boneOffset = Transforms[iter->first] * iter->second; shader.setUniformIndex(iter->first, boneOffset); iter++; }*/// bind appropriate texturesunsignedint diffuseNr =0;unsignedint specularNr =0;unsignedint normalNr =0;unsignedint heightNr =0;unsignedint aoNr =0;unsignedint metallicNr =0;unsignedint roughnessNr =0;for(unsignedint i =0; i < textures.size(); i++){
glActiveTexture(GL_TEXTURE0 + i);// active proper texture unit before binding// retrieve texture number (the N in diffuse_textureN)
string number;
string name = textures[i].type;if(name =="albedoMap"){
number = std::to_string(diffuseNr++);//cout << "+++++++++++" << textures[i].path << endl;}elseif(name =="specularMap")
number = std::to_string(specularNr++);// transfer unsigned int to streamelseif(name =="normalMap")
number = std::to_string(normalNr++);// transfer unsigned int to streamelseif(name =="heightMap")
number = std::to_string(heightNr++);// transfer unsigned int to streamelseif(name =="aoMap")
number = std::to_string(aoNr++);// transfer unsigned int to streamelseif(name =="metallicMap")
number = std::to_string(metallicNr++);// transfer unsigned int to streamelseif(name =="roughnessMap")
number = std::to_string(roughnessNr++);
string a = number.compare("0")==0? name : name + number;// now set the sampler to the correct texture unitglUniform1i(glGetUniformLocation(m_pShaderProg->ID, a.c_str()), i);// and finally bind the textureglBindTexture(GL_TEXTURE_2D, textures[i].texture2D->ID);}// draw meshglBindVertexArray(VAO);glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT,0);glBindVertexArray(0);// always good practice to set everything back to defaults once configured.glActiveTexture(GL_TEXTURE0);}
ModelComponent类
#ifndefModelComponent_H#defineModelComponent_H#include"Component.h"#include"Mesh.h"#include<assimp/Importer.hpp>#include<assimp/scene.h>#include<assimp/anim.h>#include<assimp/postprocess.h>#include<glm/gtc/matrix_transform.hpp>#include<string>#include<fstream>#include<sstream>#include<iostream>#include<map>#include<vector>usingnamespace std;classModelComponent:publicComponent{
public:
vector<Mesh> meshes;
string directory;
std::vector<VertexBoneData> Bones;unsignedint totalVertices =0;bool gammaCorrection;const aiScene* pScene;//!< The Assimp aiScene object. ModelComponent(GameObject* gameObject);voidUpdate()override;voidLateUpdate()override;voidRender()override;voidInitAnimation();voidPlayAnimation(string animaName);voidLoadModel(Shader* shader, string const& path,bool gamma);voidDraw();voidBoneTransform(float TimeInSeconds, std::vector<glm::mat4>& Transforms);//!< Traverses the scene hierarchy and fetches the matrix transformation for each bone given the time. voidSetBoneTransform(unsignedint Index,const glm::mat4& Transform);//!< Inserts a bone transformation in the uniform array at the given index. int animationIndex;float animationTime;
map<string,int> animations;private:bool _isPlay;staticconstunsignedint ui_BoneArraySize =100;
GLint m_boneLocation[ui_BoneArraySize];
Assimp::Importer importer;
string texturePath;unsignedint m_NumBones;
Shader* m_pShaderProg;
aiNode* m_RootNode;
vector<unsignedint> baseVertex;
map<unsignedint, glm::mat4>* boneOffsets;voidloadModel(string path);voidprocessNode(aiNode* node, glm::mat4 parentTransfrom);
Mesh processMesh(unsignedint meshId, aiMesh* mesh);
vector<Texture>loadMaterialTextures(aiMaterial* mat, aiTextureType type,
string typeName);
Texture2D*TextureFromFile(const string& filename);
std::map<std::string,unsignedint> m_BoneMapping;//!< Map of bone names to ids
std::vector<BoneInfo> m_BoneInfo;//!< Array containing bone information such as offset matrix and final transformation.
glm::mat4 GlobalTransformation;//!< Root node transformation.
glm::mat4 m_GlobalInverseTransform;voidLoadBones(unsignedint MeshIndex,const aiMesh* pMesh, std::vector<VertexBoneData>& Bones, std::vector<unsignedint> baseVertex, glm::mat4 nodeTransform);//!< Loads the bone data from a given mesh. voidCalcInterpolatedRotation(aiQuaternion& Out,float AnimationTime,const aiNodeAnim* pNodeAnim);//!< Calculates the interpolated quaternion between two keyframes. voidCalcInterpolatedScaling(aiVector3D& Out,float AnimationTime,const aiNodeAnim* pNodeAnim);//!< Calculates the interpolated scaling vector between two keyframes. voidCalcInterpolatedTranslation(aiVector3D& Out,float AnimationTime,const aiNodeAnim* pNodeAnim);//!< Calculates the interpolated translation vector between two keyframes. unsignedintFindRotation(float AnimationTime,const aiNodeAnim* pNodeAnim);//!< Finds a rotation key given the current animation time. unsignedintFindScale(float AnimationTime,const aiNodeAnim* pNodeAnim);// Finds a scaling key given the current animation time. unsignedintFindTranslation(float AnimationTime,const aiNodeAnim* pNodeAnim);// Finds a translation key given the current animation time. voidReadNodeHierarchy(float AnimationTime,const aiNode* pNode,const glm::mat4& ParentTransform);int _meshIndex;};#endif#endif----------------------------------#include"ModelComponent.h"#include"ResourceManager.h"#include"GameObject.h"#include"Time.h"ModelComponent::ModelComponent(GameObject* gameObject):Component(gameObject){
_isPlay =false;
_meshIndex =0;}voidModelComponent::Update(){
if(_isPlay){
animationTime +=Time::GetDeltaTime();
vector<glm::mat4> Transforms;BoneTransform(animationTime, Transforms);for(unsignedint i =0; i < Transforms.size(); i++){
SetBoneTransform(i, Transforms[i]);}}
__super::Update();}voidModelComponent::LateUpdate(){
__super::LateUpdate();}voidModelComponent::Render(){
glm::mat4 model = gameObject->transform->worldTransformMat;
m_pShaderProg->SetMatrix4("model", model,true);Draw();
__super::Render();}voidModelComponent::InitAnimation(){
for(unsignedint k =0; k < pScene->mNumAnimations; k++){
string name(pScene->mAnimations[k]->mName.data);
animations[name]= k;}
animationIndex =0;
animationTime =0.0f;
_isPlay =true;}voidModelComponent::PlayAnimation(string animaName){
if(animations.find(animaName)!= animations.end()){
animationTime =0.0f;
animationIndex = animations[animaName];}}#include<glm/gtc/quaternion.hpp>#include<glm/gtc/type_ptr.hpp>// constructor, expects a filepath to a 3D model.voidModelComponent::LoadModel(Shader* shader, string const& path,bool gamma =false){
pScene =NULL;this->gammaCorrection = gamma;this->texturePath = texturePath;
m_pShaderProg = shader;
m_NumBones =0;
totalVertices =0;
shader->Use();for(unsignedint i =0; i < ui_BoneArraySize; i++){
char Name[128];memset(Name,0,sizeof(Name));_snprintf_s(Name,sizeof(Name),"gBones[%d]", i);
m_boneLocation[i]=glGetUniformLocation(shader->ID, Name);}loadModel(path);
aiMatrix4x4 a = pScene->mRootNode->mTransformation;
m_GlobalInverseTransform = glm::transpose(glm::make_mat4(&a.a1));
m_GlobalInverseTransform = glm::inverse(m_GlobalInverseTransform);}voidModelComponent::Draw(){
for(unsignedint i =0; i < meshes.size(); i++)
meshes[i].Draw(*m_pShaderProg);}voidModelComponent::loadModel(string path){
// read file via ASSIMP//pScene = importer.ReadFile(path, aiProcess_JoinIdenticalVertices | aiProcess_SortByPType | aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FlipUVs | aiProcess_CalcTangentSpace | aiProcess_LimitBoneWeights);
pScene = importer.ReadFile(path, aiProcessPreset_TargetRealtime_Quality);
m_RootNode = pScene->mRootNode;// check for errorsif(!pScene || pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE ||!pScene->mRootNode)// if is Not Zero{
cout <<"ERROR::ASSIMP:: "<< importer.GetErrorString()<< endl;return;}// retrieve the directory path of the filepath
directory = path.substr(0, path.find_last_of('/'));
boneOffsets =new map<unsignedint, glm::mat4>[pScene->mNumMeshes];// process ASSIMP's root node recursivelyfor(unsignedint i =0; i < pScene->mNumMeshes; i++){
baseVertex.push_back(totalVertices);
totalVertices += pScene->mMeshes[i]->mNumVertices;}
Bones.resize(totalVertices);processNode(pScene->mRootNode, glm::mat4(1.0f));}voidModelComponent::processNode(aiNode* node, glm::mat4 parentTransfrom){
/*for (unsigned int i = 0; i < pScene->mNumMeshes; i++) { aiMesh* mesh = pScene->mMeshes[i]; Mesh m = processMesh(mesh); m.BaseVertex = BaseVertex; BaseVertex += pScene->mMeshes[i]->mNumVertices; meshes.push_back(m); }*/// 处理节点所有的网格(如果有的话)//for (unsigned int i = 0; i < node->mNumMeshes; i++)//{
// aiMesh* mesh = pScene->mMeshes[node->mMeshes[i]];// Mesh m = processMesh(mesh);// m.BaseVertex = BaseVertex;// BaseVertex += m.vertices.size();// meshes.push_back(m);//} 接下来对它的子节点重复这一过程//for (unsigned int i = 0; i < node->mNumChildren; i++)//{
// processNode(node->mChildren[i]);//}/*for (unsigned int i = 0; i < pScene->mNumMeshes; i++) { aiMesh* mesh = pScene->mMeshes[i]; LoadBones(i, mesh, Bones, baseVertex); meshes.push_back(processMesh(i, mesh)); }*/
aiMatrix4x4 a = node->mTransformation;
glm::mat4 nodeTransform = parentTransfrom * glm::transpose(glm::make_mat4(&a.a1));for(unsignedint i =0; i < node->mNumMeshes; i++){
cout << node->mName.data << endl;
aiMesh* mesh = pScene->mMeshes[node->mMeshes[i]];LoadBones(_meshIndex, mesh, Bones, baseVertex, nodeTransform);
meshes.push_back(processMesh(_meshIndex, mesh));
_meshIndex++;}for(unsignedint i =0; i < node->mNumChildren; i++){
processNode(node->mChildren[i], nodeTransform);}}
Mesh ModelComponent::processMesh(unsignedint meshId, aiMesh* mesh){
// data to fill
vector<Vertex> vertices;
vector<unsignedint> indices;
vector<Texture> textures;// walk through each of the mesh's verticesfor(unsignedint i =0; i < mesh->mNumVertices; i++){
Vertex vertex;
glm::vec3 vector;// we declare a placeholder vector since assimp uses its own vector class that doesn't directly convert to glm's vec3 class so we transfer the data to this placeholder glm::vec3 first.// positions
vector.x = mesh->mVertices[i].x;
vector.y = mesh->mVertices[i].y;
vector.z = mesh->mVertices[i].z;
vertex.Position = vector;// normalsif(mesh->HasNormals()){
vector.x = mesh->mNormals[i].x;
vector.y = mesh->mNormals[i].y;
vector.z = mesh->mNormals[i].z;
vertex.Normal = vector;}// texture coordinatesif(mesh->mTextureCoords[0])// does the mesh contain texture coordinates?{
glm::vec2 vec;// a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't // use models where a vertex can have multiple texture coordinates so we always take the first set (0).
vec.x = mesh->mTextureCoords[0][i].x;
vec.y = mesh->mTextureCoords[0][i].y;
vertex.TexCoords = vec;// tangentif(mesh->mTangents !=NULL){
vector.x = mesh->mTangents[i].x;
vector.y = mesh->mTangents[i].y;
vector.z = mesh->mTangents[i].z;
vertex.Tangent = vector;}if(mesh->mBitangents !=NULL){
vector.x = mesh->mBitangents[i].x;
vector.y = mesh->mBitangents[i].y;
vector.z = mesh->mBitangents[i].z;
vertex.Bitangent = vector;}// bitangent}else
vertex.TexCoords = glm::vec2(0.0f,0.0f);
vertices.push_back(vertex);}// now wak through each of the mesh's faces (a face is a mesh its triangle) and retrieve the corresponding vertex indices.for(unsignedint i =0; i < mesh->mNumFaces; i++){
aiFace face = mesh->mFaces[i];// retrieve all indices of the face and store them in the indices vectorfor(unsignedint j =0; j < face.mNumIndices; j++)
indices.push_back(face.mIndices[j]);}// process materials
aiMaterial* material = pScene->mMaterials[mesh->mMaterialIndex];// we assume a convention for sampler names in the shaders. Each diffuse texture should be named// as 'texture_diffuseN' where N is a sequential number ranging from 1 to MAX_SAMPLER_NUMBER. // Same applies to other texture as the following list summarizes:// diffuse: texture_diffuseN// specular: texture_specularN// normal: texture_normalN// 1. diffuse maps
vector<Texture> diffuseMaps =loadMaterialTextures(material, aiTextureType::aiTextureType_DIFFUSE,"albedoMap");
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());// 2. specular maps
vector<Texture> specularMaps =loadMaterialTextures(material, aiTextureType_SPECULAR,"specularMap");
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());// 3. normal maps
std::vector<Texture> normalMaps =loadMaterialTextures(material, aiTextureType_NORMALS,"normalMap");
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());// 4. height maps
std::vector<Texture> heightMaps =loadMaterialTextures(material, aiTextureType::aiTextureType_HEIGHT,"heightMap");
textures.insert(textures.end(), heightMaps.begin(), heightMaps.end());// 5. Ao maps
std::vector<Texture> aoMaps =loadMaterialTextures(material, aiTextureType::aiTextureType_AMBIENT_OCCLUSION,"aoMap");
textures.insert(textures.end(), aoMaps.begin(), aoMaps.end());// 6. metallicMap
std::vector<Texture> metallicMaps =loadMaterialTextures(material, aiTextureType::aiTextureType_METALNESS,"metallicMap");
textures.insert(textures.end(), metallicMaps.begin(), metallicMaps.end());// 7. roughnessMap
std::vector<Texture> roughnessMaps =loadMaterialTextures(material, aiTextureType::aiTextureType_DIFFUSE_ROUGHNESS,"roughnessMap");
textures.insert(textures.end(), roughnessMaps.begin(), roughnessMaps.end());int offset = baseVertex[meshId];// return a mesh object created from the extracted mesh datareturnMesh(vertices, indices, textures, offset, Bones , m_pShaderProg);}
vector<Texture>ModelComponent::loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName){
vector<Texture> textures;for(unsignedint i =0; i < mat->GetTextureCount(type); i++){
aiString str;
mat->GetTexture(type, i,&str);
string s = str.C_Str();int a = s.find_last_of('\\')+1;if(a ==0)
a = s.find_last_of('/')+1;
string b = s.substr(a, s.length()- a);
string filename = directory +'/'+ b;
Texture texture;// check if texture was loaded before and if so, continue to next iteration: skip loading a new textureif(ResourceManager::HaveTexture(filename)){
texture.haveData =true;
texture.texture2D =ResourceManager::GetTextureP(filename);
texture.type = typeName;
texture.path = filename;}else{
if(ResourceManager::IsFileExistent(filename)){
texture.haveData =true;
texture.texture2D =TextureFromFile(filename);
texture.type = typeName;
texture.path = filename;}else{
cout << filename << endl;
texture.haveData =false;
texture.type = typeName;
texture.path = filename;}}if(texture.haveData)
textures.push_back(texture);}return textures;}
Texture2D*ModelComponent::TextureFromFile(const string& filename){
ResourceManager::LoadTexture(filename.c_str(), filename);returnResourceManager::GetTextureP(filename);}voidModelComponent::LoadBones(unsignedint MeshIndex,const aiMesh* pMesh, std::vector<VertexBoneData>& Bones, std::vector<unsignedint> baseVertex, glm::mat4 nodeTransform){
// Loop through all bones in the Assimp mesh.for(unsignedint i =0; i < pMesh->mNumBones; i++){
unsignedint BoneIndex =0;// Obtain the bone name.
std::string BoneName(pMesh->mBones[i]->mName.data);// If bone isn't already in the map. if(m_BoneMapping.find(BoneName)== m_BoneMapping.end()){
// Set the bone ID to be the current total number of bones.
BoneIndex = m_NumBones;// Increment total bones.
m_NumBones++;// Push new bone info into bones vector.
BoneInfo bi;
m_BoneInfo.push_back(bi);}else{
// Bone ID is already in map.
BoneIndex = m_BoneMapping[BoneName];}
m_BoneMapping[BoneName]= BoneIndex;auto Offset = pMesh->mBones[i]->mOffsetMatrix;// Obtains the offset matrix which transforms the bone from mesh space into bone space.
m_BoneInfo[BoneIndex].SetBoneOffset(glm::transpose(glm::make_mat4(&Offset.a1)));//boneOffsets[MeshIndex][BoneIndex] = glm::transpose(glm::make_mat4(&Offset.a1));// Iterate over all the affected vertices by this bone i.e weights. for(unsignedint j =0; j < pMesh->mBones[i]->mNumWeights; j++){
// Obtain an index to the affected vertex within the array of vertices.unsignedint VertexID = baseVertex[MeshIndex]+ pMesh->mBones[i]->mWeights[j].mVertexId;// The value of how much this bone influences the vertex. float Weight = pMesh->mBones[i]->mWeights[j].mWeight;// Insert bone data for particular vertex ID. A maximum of 4 bones can influence the same vertex.
Bones[VertexID].AddBoneData(BoneIndex, Weight);}//for (unsigned int j = 0; j < pMesh->mNumVertices; j++) {
// // Obtain an index to the affected vertex within the array of vertices.// unsigned int VertexID = baseVertex[MeshIndex] + j;// // The value of how much this bone influences the vertex. // float Weight = pMesh->mBones[i]->mWeights[j].mWeight;// // Insert bone data for particular vertex ID. A maximum of 4 bones can influence the same vertex. // Bones[VertexID].AddBoneData(BoneIndex, 1.0f);//}}}voidModelComponent::BoneTransform(float TimeInSeconds, std::vector<glm::mat4>& Transforms){
glm::mat4 Identity;
Identity = glm::mat4(1.0f);/*unsigned int numPosKeys = pScene->mAnimations[0]->mChannels[0]->mNumPositionKeys; double animDuration = pScene->mAnimations[0]->mChannels[0]->mPositionKeys[numPosKeys - 1].mTime; float ticksPerSecond = (float)(pScene->mAnimations[0]->mTicksPerSecond != 0 ? pScene->mAnimations[0]->mTicksPerSecond : 25.0f); float timeInTicks = TimeInSeconds * ticksPerSecond; float AnimationTime = std::fmod(timeInTicks, animDuration);*/float TicksPerSecond = pScene->mAnimations[animationIndex]->mTicksPerSecond;float TimeInTicks = TimeInSeconds * TicksPerSecond;float AnimationTime =fmod(TimeInTicks, pScene->mAnimations[animationIndex]->mDuration);ReadNodeHierarchy(AnimationTime, pScene->mRootNode, Identity);
Transforms.resize(m_NumBones);// Populates transforms vector with new bone transformation matrices. for(unsignedint i =0; i < m_NumBones; i++){
Transforms[i]= m_BoneInfo[i].FinalTransformation;}}unsignedintModelComponent::FindRotation(float AnimationTime,const aiNodeAnim* pNodeAnim){
// Check if there are rotation keyframes. assert(pNodeAnim->mNumRotationKeys >0);// Find the rotation key just before the current animation time and return the index. for(unsignedint i =0; i < pNodeAnim->mNumRotationKeys -1; i++){
if(AnimationTime <(float)pNodeAnim->mRotationKeys[i +1].mTime){
return i;}}//assert(0);return pNodeAnim->mNumRotationKeys -1;}unsignedintModelComponent::FindScale(float AnimationTime,const aiNodeAnim* pNodeAnim){
assert(pNodeAnim->mNumScalingKeys >0);// Find the scaling key just before the current animation time and return the index. for(unsignedint i =0; i < pNodeAnim->mNumScalingKeys -1; i++){
if(AnimationTime <(float)pNodeAnim->mScalingKeys[i +1].mTime){
return i;}}//assert(0);return pNodeAnim->mNumScalingKeys -1;}unsignedintModelComponent::FindTranslation(float AnimationTime,const aiNodeAnim* pNodeAnim){
assert(pNodeAnim->mNumPositionKeys >0);// Find the translation key just before the current animation time and return the index. for(unsignedint i =0; i < pNodeAnim->mNumPositionKeys -1; i++){
if(AnimationTime <(float)pNodeAnim->mPositionKeys[i +1].mTime){
return i;}}//assert(0);return pNodeAnim->mNumPositionKeys -1;}voidModelComponent::CalcInterpolatedScaling(aiVector3D& Out,float AnimationTime,const aiNodeAnim* pNodeAnim){
if(pNodeAnim->mNumScalingKeys ==1){
Out = pNodeAnim->mScalingKeys[0].mValue;return;}unsignedint ScalingIndex =FindScale(AnimationTime, pNodeAnim);if(ScalingIndex == pNodeAnim->mNumScalingKeys -1){
//Out = pNodeAnim->mRotationKeys[0].mValue;
Out = pNodeAnim->mScalingKeys[pNodeAnim->mNumScalingKeys -1].mValue;return;}unsignedint NextScalingIndex =(ScalingIndex +1);assert(NextScalingIndex < pNodeAnim->mNumScalingKeys);float DeltaTime =(float)(pNodeAnim->mScalingKeys[NextScalingIndex].mTime - pNodeAnim->mScalingKeys[ScalingIndex].mTime);float Factor =(AnimationTime -(float)pNodeAnim->mScalingKeys[ScalingIndex].mTime)/ DeltaTime;assert(Factor >=0.0f&& Factor <=1.0f);const aiVector3D& Start = pNodeAnim->mScalingKeys[ScalingIndex].mValue;const aiVector3D& End = pNodeAnim->mScalingKeys[NextScalingIndex].mValue;
aiVector3D Delta = End - Start;
Out = Start + Factor * Delta;}voidModelComponent::CalcInterpolatedRotation(aiQuaternion& Out,float AnimationTime,const aiNodeAnim* pNodeAnim){
// we need at least two values to interpolate...if(pNodeAnim->mNumRotationKeys ==1){
Out = pNodeAnim->mRotationKeys[0].mValue;return;}// Obtain the current rotation keyframe. unsignedint RotationIndex =FindRotation(AnimationTime, pNodeAnim);if(RotationIndex == pNodeAnim->mNumRotationKeys -1){
//Out = pNodeAnim->mRotationKeys[0].mValue;
Out = pNodeAnim->mRotationKeys[pNodeAnim->mNumRotationKeys -1].mValue;return;}// Calculate the next rotation keyframe and check bounds. unsignedint NextRotationIndex =(RotationIndex +1);assert(NextRotationIndex < pNodeAnim->mNumRotationKeys);// Calculate delta time, i.e time between the two keyframes.float DeltaTime = pNodeAnim->mRotationKeys[NextRotationIndex].mTime - pNodeAnim->mRotationKeys[RotationIndex].mTime;// Calculate the elapsed time within the delta time. float Factor =(AnimationTime -(float)pNodeAnim->mRotationKeys[RotationIndex].mTime)/ DeltaTime;//assert(Factor >= 0.0f && Factor <= 1.0f);// Obtain the quaternions values for the current and next keyframe. const aiQuaternion& StartRotationQ = pNodeAnim->mRotationKeys[RotationIndex].mValue;const aiQuaternion& EndRotationQ = pNodeAnim->mRotationKeys[NextRotationIndex].mValue;// Interpolate between them using the Factor.
aiQuaternion::Interpolate(Out, StartRotationQ, EndRotationQ, Factor);// Normalise and set the reference.
Out = Out.Normalize();}voidModelComponent::CalcInterpolatedTranslation(aiVector3D& Out,float AnimationTime,const aiNodeAnim* pNodeAnim){
// we need at least two values to interpolate...if(pNodeAnim->mNumPositionKeys ==1){
Out = pNodeAnim->mPositionKeys[0].mValue;return;}unsignedint PositionIndex =FindTranslation(AnimationTime, pNodeAnim);if(PositionIndex == pNodeAnim->mNumPositionKeys -1){
//Out = pNodeAnim->mPositionKeys[0].mValue;
Out = pNodeAnim->mPositionKeys[pNodeAnim->mNumPositionKeys -1].mValue;return;}unsignedint NextPositionIndex =(PositionIndex +1);assert(NextPositionIndex < pNodeAnim->mNumPositionKeys);float DeltaTime = pNodeAnim->mPositionKeys[NextPositionIndex].mTime - pNodeAnim->mPositionKeys[PositionIndex].mTime;float Factor =(AnimationTime -(float)pNodeAnim->mPositionKeys[PositionIndex].mTime)/ DeltaTime;//assert(Factor >= 0.0f && Factor <= 1.0f);const aiVector3D& Start = pNodeAnim->mPositionKeys[PositionIndex].mValue;const aiVector3D& End = pNodeAnim->mPositionKeys[NextPositionIndex].mValue;
aiVector3D Delta = End - Start;
Out = Start + Factor * Delta;}voidModelComponent::SetBoneTransform(unsignedint Index,const glm::mat4& Transform){
assert(Index <100);/*glm::mat4 a = glm::transpose(Transform);*/glUniformMatrix4fv(m_boneLocation[Index],1, GL_FALSE,&Transform[0][0]);//m_pShaderProg->setUniformIndex(Index, Transform);}voidModelComponent::ReadNodeHierarchy(float AnimationTime,const aiNode* pNode,const glm::mat4& ParentTransform){
glm::mat4 IdentityTest;
IdentityTest = glm::mat4(1.0f);// Obtain the name of the current node
std::string NodeName(pNode->mName.data);// Use the first animation const aiAnimation* pAnimation = pScene->mAnimations[animationIndex];// Obtain transformation relative to node's parent. auto a = pNode->mTransformation;
glm::mat4 NodeTransformation = glm::transpose(glm::make_mat4(&a.a1));/*if (NodeName.find("$AssimpFbx$") != NodeName.npos) NodeTransformation = glm::mat4(1.0f);*/const aiNodeAnim* pNodeAnim =NULL;// Find the animation channel of the current node. for(unsigned i =0; i < pAnimation->mNumChannels; i++){
const aiNodeAnim* pNodeAnimIndex = pAnimation->mChannels[i];// If there is a match for a channel with the current node's name, then we've found the animation channel. if(std::string(pNodeAnimIndex->mNodeName.data)== NodeName){
pNodeAnim = pNodeAnimIndex;}}if(pNodeAnim){
Interpolate scaling and generate scaling transformation matrix
aiVector3D Scaling;CalcInterpolatedScaling(Scaling, AnimationTime, pNodeAnim);
glm::mat4 ScalingM;
ScalingM = glm::scale(glm::mat4(1.0f), glm::vec3(Scaling.x, Scaling.y, Scaling.z));// Interpolate rotation and generate rotation transformation matrix
aiQuaternion RotationQ;CalcInterpolatedRotation(RotationQ, AnimationTime, pNodeAnim);
glm::quat rotation = glm::quat(RotationQ.w, RotationQ.x, RotationQ.y, RotationQ.z);
glm::mat4 RotationM = glm::mat4_cast(rotation);/*aiQuaternion RotationQ; CalcInterpolatedRotation(RotationQ, AnimationTime, pNodeAnim); auto c = RotationQ.GetMatrix(); glm::mat4 RotationM = ai_to_glm2(c);*/// Interpolate translation and generate translation transformation matrix
aiVector3D Translation;CalcInterpolatedTranslation(Translation, AnimationTime, pNodeAnim);
glm::mat4 TranslationM;
TranslationM = glm::translate(IdentityTest, glm::vec3(Translation.x, Translation.y, Translation.z));// Combine the above transformations
NodeTransformation = TranslationM * RotationM * ScalingM;//NodeTransformation = glm::mat4(1.0f);}
glm::mat4 GlobalTransformation2 = ParentTransform * NodeTransformation;// Apply the final transformation to the indexed bone in the array. if(m_BoneMapping.find(NodeName)!= m_BoneMapping.end()){
unsignedint BoneIndex = m_BoneMapping[NodeName];//m_BoneInfo[BoneIndex].FinalTransformation = GlobalTransformation2;
m_BoneInfo[BoneIndex].FinalTransformation = GlobalTransformation2 * m_BoneInfo[BoneIndex].BoneOffset;}// Do the same for all the node's children. for(unsigned i =0; i < pNode->mNumChildren; i++){
ReadNodeHierarchy(AnimationTime, pNode->mChildren[i], GlobalTransformation2);}}
文章评论