18 #include <ResourceManager.h> 22 #include <assimp/Importer.hpp> 23 #include <assimp/postprocess.h> 24 #include <assimp/scene.h> 30 #include "BoneMatrices.h" 32 #include "linmath/float3x3.h" 33 #include "BoneTransformer.h" 37 #define BONE_ID_LOCATION_GPU 6 38 #define BONE_WEIGHT_LOCATION_GPU 7 44 void Mesh::loadMesh(
const std::string &fileName) {
45 Logger::logInfo(
"Loading mesh " + fileName);
48 fileName.c_str(), aiProcess_GenSmoothNormals | aiProcess_Triangulate | aiProcess_CalcTangentSpace);
49 aiScene* aiScene = importer.GetOrphanedScene();
52 Logger::logError(
"Error loading mesh for " + fileName +
". Error message: " + importer.GetErrorString());
54 boneTransformer = std::make_shared<BoneTransformer>(
BoneTransformer(aiScene));
55 initMesh(aiScene, fileName);
59 void Mesh::initMesh(
const aiScene *assimpScene,
const std::string &fileNameOfMesh) {
60 for (
unsigned int i = 0; i < assimpScene->mNumMeshes; i++) {
61 const aiMesh *paiMesh = assimpScene->mMeshes[i];
62 initMeshFromAiMesh(i, paiMesh);
65 initMaterials(assimpScene, fileNameOfMesh);
68 numAnimations = assimpScene->mNumAnimations;
72 void Mesh::initMeshFromAiMesh(
unsigned int index,
const aiMesh *paiMesh) {
75 initChunkFromAiMesh(paiMesh, chunk);
76 setupSphere(&chunk.m_positions);
79 void Mesh::initChunkFromAiMesh(
const aiMesh *paiMesh,
Chunk &chunk) {
80 initVerticesFromAiMesh(paiMesh, chunk);
81 initIndicesFromAiMesh(paiMesh, chunk);
83 initBonesFromAiMesh(paiMesh, chunk);
86 chunk.materialIndex = paiMesh->mMaterialIndex;
88 setupChunkForRendering(chunk);
89 m_chunks.push_back(chunk);
93 void Mesh::assertAllVertexWeightsSumToOne(
Chunk &chunk) {
94 for(
unsigned int i = 0; i < chunk.bones.size(); i++) {
97 for (
int boneIndex = 0; boneIndex < MAX_NUM_BONES; boneIndex++) {
98 sum += boneInfluenceOnVertex.weights[boneIndex];
101 assert(fequals(sum, 1.0f));
106 void Mesh::initVerticesFromAiMesh(
const aiMesh *paiMesh,
Chunk &chunk) {
107 const aiVector3D Zero3D(0.0f, 0.0f, 0.0f);
109 for (
unsigned int i = 0; i < paiMesh->mNumVertices; i++) {
110 const aiVector3D pPos = paiMesh->mVertices[i];
111 const aiVector3D pNormal = paiMesh->mNormals[i];
112 const aiVector3D pTexCoord = paiMesh->HasTextureCoords(0) ? paiMesh->mTextureCoords[0][i] : Zero3D;
114 chunk.m_positions.push_back(make_vector(pPos.x, pPos.y, pPos.z));
115 chunk.m_normals.push_back(make_vector(pNormal.x, pNormal.y, pNormal.z));
116 chunk.m_uvs.push_back(make_vector(pTexCoord.x, pTexCoord.y));
118 if (paiMesh->HasTangentsAndBitangents()) {
119 const aiVector3D pBitTangents = paiMesh->mBitangents[i];
120 const aiVector3D pTangents = paiMesh->mTangents[i];
121 chunk.m_bittangents.push_back(make_vector(pBitTangents.x, pBitTangents.y, pBitTangents.z));
122 chunk.m_tangents.push_back(make_vector(pTangents.x, pTangents.y, pTangents.z));
125 updateMinAndMax(pPos.x, pPos.y, pPos.z, &m_aabb.minV, &m_aabb.maxV);
129 void Mesh::initIndicesFromAiMesh(
const aiMesh *paiMesh,
Chunk &chunk) {
130 for (
unsigned int i = 0; i < paiMesh->mNumFaces; i++) {
131 const aiFace face = paiMesh->mFaces[i];
132 chunk.m_indices.push_back(face.mIndices[0]);
133 chunk.m_indices.push_back(face.mIndices[1]);
134 chunk.m_indices.push_back(face.mIndices[2]);
138 void Mesh::initBonesFromAiMesh(
const aiMesh *paiMesh,
Chunk &chunk) {
139 if(paiMesh->mNumBones == 0) {
143 chunk.bones.resize(paiMesh->mNumVertices);
146 for(
unsigned int i = 0; i < paiMesh->mNumBones; i++) {
148 boneIndex = boneTransformer->createBoneIndexIfAbsent(paiMesh->mBones[i]);
150 for (
unsigned int j = 0; j < paiMesh->mBones[i]->mNumWeights; j++) {
151 auto aiWeight = paiMesh->mBones[i]->mWeights[j];
152 uint vertexId = aiWeight.mVertexId;
153 float weight = aiWeight.mWeight;
155 chunk.bones[vertexId].addBoneData(boneIndex, weight);
159 assertAllVertexWeightsSumToOne(chunk);
162 void Mesh::initMaterials(
const aiScene *pScene,
const std::string &fileNameOfMesh) {
163 for (
unsigned int i = 0; i < pScene->mNumMaterials; i++) {
164 const aiMaterial *material = pScene->mMaterials[i];
167 initMaterialTextures(&m, fileNameOfMesh, material);
168 initMaterialColors(&m, material);
169 initMaterialShininess(&m, material);
171 materials.push_back(m);
175 void Mesh::initMaterialTextures(
Material *material, std::string fileNameOfMesh,
const aiMaterial *loadedMaterial) {
176 if (loadedMaterial->GetTextureCount(aiTextureType_DIFFUSE) > 0) {
177 material->diffuseTexture = getTexture(loadedMaterial, fileNameOfMesh, aiTextureType_DIFFUSE);
179 if (loadedMaterial->GetTextureCount(aiTextureType_HEIGHT) > 0) {
180 material->bumpMapTexture = getTexture(loadedMaterial, fileNameOfMesh, aiTextureType_HEIGHT);
184 void Mesh::initMaterialColors(
Material *material,
const aiMaterial *loadedMaterial) {
185 material->ambientColor = getColorFromMaterial(AI_MATKEY_COLOR_AMBIENT, *loadedMaterial);
186 material->diffuseColor = getColorFromMaterial(AI_MATKEY_COLOR_DIFFUSE, *loadedMaterial);
187 material->specularColor = getColorFromMaterial(AI_MATKEY_COLOR_SPECULAR, *loadedMaterial);
188 material->emissiveColor = getColorFromMaterial(AI_MATKEY_COLOR_EMISSIVE, *loadedMaterial);
191 void Mesh::initMaterialShininess(
Material *material,
const aiMaterial *loadedMaterial) {
193 loadedMaterial->Get(AI_MATKEY_SHININESS, specExp);
194 material->specularExponent = specExp > 0.0f ? specExp : 0.0f;
197 float3 Mesh::getColorFromMaterial(
const char* colorTypeString,
unsigned int type,
unsigned int index,
const aiMaterial &material) {
199 material.Get(colorTypeString, type, index, color);
200 return make_vector(color.r, color.g, color.b);
203 Texture *Mesh::getTexture(
const aiMaterial *material,
const std::string &fileNameOfMesh, aiTextureType type) {
204 aiString texturePath;
205 if (material->GetTexture(type, 0, &texturePath, NULL, NULL, NULL, NULL, NULL) != AI_SUCCESS) {
209 std::string absolutePath = getPathOfTexture(fileNameOfMesh, std::string(texturePath.data));
210 return ResourceManager::loadAndFetchTexture(absolutePath);
213 std::string Mesh::getPathOfTexture(
const std::string &fileName, std::string textureName) {
214 std::string dir = getDirectoryFromPath(fileName);
215 std::string filePath = cleanFileName(textureName);
216 return dir +
"/" + filePath;
219 std::string Mesh::getDirectoryFromPath(
const std::string &fileName) {
220 std::string::size_type index = fileName.find_last_of(
"/");
221 if (index == std::string::npos) {
223 }
else if (index == 0) {
226 return fileName.substr(0, index);
230 std::string Mesh::cleanFileName(std::string fileName) {
231 if (fileName.substr(0, 2) ==
".\\") {
232 return fileName.substr(2, fileName.size() - 2);
242 void Mesh::setupSphere(std::vector<float3> *positions) {
243 sphere.setPosition(m_aabb.getCenterPosition());
244 sphere.setRadius(0.0f);
245 for (float3 posIt : *positions) {
246 float rad = length(sphere.getPosition() - posIt);
247 if (rad > sphere.getRadius()) {
248 sphere.setRadius(rad);
255 template <
typename T>
256 void setupGlBuffer(std::vector<T> buffer, GLuint *bufferGLObject, GLuint vertexAttibute,
int numbersPerObject,
257 const void* firstObject, GLenum bufferType, GLuint dataType) {
258 glGenBuffers(1, bufferGLObject);
259 glBindBuffer(bufferType, *bufferGLObject);
260 glBufferData(bufferType, buffer.size() *
sizeof(buffer[0]), firstObject, GL_STATIC_DRAW);
261 glVertexAttribPointer(vertexAttibute, numbersPerObject, dataType, GL_FALSE, 0, 0);
262 glEnableVertexAttribArray(vertexAttibute);
265 void Mesh::setupChunkForRendering(
Chunk &chunk) {
266 glGenVertexArrays(1, &chunk.m_vaob);
267 glBindVertexArray(chunk.m_vaob);
269 setupGlBuffer(chunk.m_positions, &chunk.m_positions_bo, 0, 3 , &chunk.m_positions[0].x, GL_ARRAY_BUFFER_ARB, GL_FLOAT);
270 setupGlBuffer(chunk.m_normals, &chunk.m_normals_bo, 1, 3, &chunk.m_normals[0].x, GL_ARRAY_BUFFER_ARB, GL_FLOAT);
272 if (chunk.m_uvs.size() > 0) {
273 setupGlBuffer(chunk.m_uvs, &chunk.m_uvs_bo, 2, 2, &chunk.m_uvs[0].x, GL_ARRAY_BUFFER_ARB, GL_FLOAT);
276 setupGlBuffer(chunk.m_indices, &chunk.m_ind_bo, 3, 3, &chunk.m_indices[0], GL_ELEMENT_ARRAY_BUFFER_ARB, GL_FLOAT);
278 if (chunk.m_bittangents.size() > 0) {
279 setupGlBuffer(chunk.m_tangents, &chunk.m_tangents_bo, 4, 3, &chunk.m_tangents[0].x, GL_ARRAY_BUFFER_ARB, GL_FLOAT);
280 setupGlBuffer(chunk.m_bittangents, &chunk.m_bittangents_bo, 5, 3,
281 &chunk.m_bittangents[0].x, GL_ARRAY_BUFFER_ARB, GL_FLOAT);
284 if(chunk.bones.size() > 0 ) {
285 glGenBuffers(1, &chunk.bonesBufferObject);
286 glBindBuffer(GL_ARRAY_BUFFER, chunk.bonesBufferObject);
287 glBufferData(GL_ARRAY_BUFFER, chunk.bones.size() *
sizeof(chunk.bones[0]), &chunk.bones[0], GL_STATIC_DRAW);
289 const int boneIdsPerObject = 4;
290 glVertexAttribIPointer(BONE_ID_LOCATION_GPU, boneIdsPerObject, GL_INT,
sizeof(
BoneInfluenceOnVertex), 0);
291 glEnableVertexAttribArray(BONE_ID_LOCATION_GPU);
293 const int boneWeightsPerObject = 4;
294 glVertexAttribPointer(BONE_WEIGHT_LOCATION_GPU, boneWeightsPerObject, GL_FLOAT, GL_FALSE,
sizeof(
BoneInfluenceOnVertex), (
const GLvoid*)16);
295 glEnableVertexAttribArray(BONE_WEIGHT_LOCATION_GPU);
303 void Mesh::createTriangles() {
304 for (
unsigned int i = 0; i < m_chunks.size(); i++) {
306 for (
unsigned int j = 0; j + 2 < m_chunks[i].m_indices.size(); j += 3) {
307 triangles.push_back(createTriangleFromPositions(m_chunks[i].m_positions, m_chunks[i].m_indices, j));
312 Triangle* Mesh::createTriangleFromPositions(std::vector<chag::float3> positionBuffer, std::vector<unsigned int> indices,
unsigned int startIndex) {
314 return new Triangle(make_vector(positionBuffer[indices[startIndex + 0]].x,
315 positionBuffer[indices[startIndex + 0]].y,
316 positionBuffer[indices[startIndex + 0]].z),
317 make_vector(positionBuffer[indices[startIndex + 1]].x,
318 positionBuffer[indices[startIndex + 1]].y,
319 positionBuffer[indices[startIndex + 1]].z),
320 make_vector(positionBuffer[indices[startIndex + 2]].x,
321 positionBuffer[indices[startIndex + 2]].y,
322 positionBuffer[indices[startIndex + 2]].z));
329 std::vector<Chunk>* Mesh::getChunks() {
333 std::vector<Material>* Mesh::getMaterials() {
337 bool Mesh::hasAnimations() {
338 return numAnimations != 0;
342 return boneTransformer->calculateBoneTransforms(totalElapsedTimeInSeconds);
std::vector< Triangle * > getTriangles()
std::vector< chag::float4x4 > getBoneTransforms(float totalElapsedTimeInSeconds)
Struct for maintaining information of how a bone affects a vertex.