SkeletalAnimationModelLoader::MeshFrame SkeletalAnimationModelLoader::getMeshFrame(const MeshExtended &mesh) const { MeshFrame meshFrame(mesh); //Calculate new frame vertices and normals for (unsigned int cb = 0; cb < mesh.boneWeights.size(); cb++) { const auto &boneWeights = mesh.boneWeights[cb]; aiMatrix4x4 transformat = transformation; const std::function<void(unsigned int)> calculateBoneTransformation = [&](unsigned int boneId) { if (bones[boneId].hasParentBoneId) { calculateBoneTransformation(bones[boneId].parentBoneId); } transformat *= bones[boneId].transformation; }; calculateBoneTransformation(boneWeights.boneId); transformat *= boneWeights.offsetMatrix; for (auto &weight : boneWeights.weights) { meshFrame.vertices[weight.mVertexId] += weight.mWeight * (transformat * mesh.vertices[weight.mVertexId]); meshFrame.normals[weight.mVertexId] += weight.mWeight * (aiMatrix3x3(transformat) * mesh.normals[weight.mVertexId]); meshFrame.tangents[weight.mVertexId] += weight.mWeight * (aiMatrix3x3(transformat) * mesh.tangents[weight.mVertexId]); } } return meshFrame; }
void ofxAssimpModelLoader::updateBones() { // update mesh position for the animation for(unsigned int i=0; i<modelMeshes.size(); ++i) { // current mesh we are introspecting const aiMesh* mesh = modelMeshes[i].mesh; // calculate bone matrices vector<aiMatrix4x4> boneMatrices(mesh->mNumBones); for(unsigned int a=0; a<mesh->mNumBones; ++a) { const aiBone* bone = mesh->mBones[a]; // find the corresponding node by again looking recursively through the node hierarchy for the same name aiNode* node = scene->mRootNode->FindNode(bone->mName); // start with the mesh-to-bone matrix boneMatrices[a] = bone->mOffsetMatrix; // and now append all node transformations down the parent chain until we're back at mesh coordinates again const aiNode* tempNode = node; while(tempNode) { // check your matrix multiplication order here!!! boneMatrices[a] = tempNode->mTransformation * boneMatrices[a]; // boneMatrices[a] = boneMatrices[a] * tempNode->mTransformation; tempNode = tempNode->mParent; } modelMeshes[i].hasChanged = true; modelMeshes[i].validCache = false; } modelMeshes[i].animatedPos.assign(modelMeshes[i].animatedPos.size(), aiVector3D(0.0f)); if(mesh->HasNormals()){ modelMeshes[i].animatedNorm.assign(modelMeshes[i].animatedNorm.size(), aiVector3D(0.0f)); } // loop through all vertex weights of all bones for(unsigned int a=0; a<mesh->mNumBones; ++a) { const aiBone* bone = mesh->mBones[a]; const aiMatrix4x4& posTrafo = boneMatrices[a]; for(unsigned int b=0; b<bone->mNumWeights; ++b) { const aiVertexWeight& weight = bone->mWeights[b]; size_t vertexId = weight.mVertexId; const aiVector3D& srcPos = mesh->mVertices[vertexId]; modelMeshes[i].animatedPos[vertexId] += weight.mWeight * (posTrafo * srcPos); } if(mesh->HasNormals()){ // 3x3 matrix, contains the bone matrix without the translation, only with rotation and possibly scaling aiMatrix3x3 normTrafo = aiMatrix3x3( posTrafo); for(unsigned int b=0; b<bone->mNumWeights; ++b) { const aiVertexWeight& weight = bone->mWeights[b]; size_t vertexId = weight.mVertexId; const aiVector3D& srcNorm = mesh->mNormals[vertexId]; modelMeshes[i].animatedNorm[vertexId] += weight.mWeight * (normTrafo * srcNorm); } } } } }
void MeshLoader::RenderMesh(const aiNode* node) { aiMatrix4x4 Mx = mAnimator->GetLocalTransform(node); Mx.Transpose(); glPushMatrix(); glMultMatrixf((float*)&Mx); for (unsigned int i = 0; i < node->mNumMeshes; i++) { const aiMesh* mesh = m_Scene->mMeshes[node->mMeshes[i]]; std::vector<aiVector3D> CachedPosition(mesh->mNumVertices); std::vector<aiVector3D> CachedNormal(mesh->mNumVertices); if (mesh->HasBones()) { const std::vector<aiMatrix4x4>& boneMatrices = mAnimator->GetBoneMatrices(node, i); for (unsigned int a = 0; a < mesh->mNumBones; a++) { const aiBone *bone = mesh->mBones[a]; const aiMatrix4x4& posTrafo = boneMatrices[a]; aiMatrix3x3 normTrafo = aiMatrix3x3(posTrafo); for (unsigned int b = 0; b < bone->mNumWeights; b++) { const aiVertexWeight& weight = bone->mWeights[b]; unsigned int vertexId = weight.mVertexId; const aiVector3D& srcPos = mesh->mVertices[vertexId]; const aiVector3D& srcNorm = mesh->mNormals[vertexId]; CachedPosition[vertexId] += weight.mWeight * (posTrafo * srcPos); CachedNormal[vertexId] += weight.mWeight * (normTrafo * srcNorm); } } } ApplyMaterial(m_Scene->mMaterials[mesh->mMaterialIndex]); for (unsigned int j = 0; j < mesh->mNumFaces; ++j) { const aiFace* face = &mesh->mFaces[j]; glBegin(GL_TRIANGLES); for (unsigned int k = 0; k < face->mNumIndices; k++) { int v_index = face->mIndices[k]; if (mesh->mColors[0] != NULL) glColor4fv((GLfloat*)&mesh->mColors[0][v_index]); if (mesh->mNormals != NULL) glNormal3fv(&CachedNormal[v_index].x); glVertex3fv(&CachedPosition[v_index].x); } glEnd(); } } for (unsigned int i = 0; i < node->mNumChildren; i++) { RenderMesh(node->mChildren[i]); } glPopMatrix(); }
Model::Model(){ yUp = false; modelScale = 1.0; MODEL_ROT_MAT = aiMatrix3x3( 1, 0, 0, 0, 0, 1, 0, -1, 0 ); gettingVertsAndNormals = false; }
void AssimpModelMover::updateSkeleton() { // update mesh position for the animation for (unsigned int i = 0; i < modelMeshes.size(); ++i) { // current mesh we are introspecting const aiMesh *mesh = modelMeshes[i].mesh; // calculate bone matrices std::vector<ofMatrix4x4> boneMatrices(mesh->mNumBones); for (size_t a = 0; a < mesh->mNumBones; ++a) { const aiBone *bone = mesh->mBones[a]; // find the corresponding node by again looking recursively through the node hierarchy for the same name map<string, BoneNode *>::iterator it = boneNodes.find(bone->mName.data); assert(it != boneNodes.end()); BoneNode *bn = it->second; // start with the mesh-to-bone matrix //boneMatrices[a] = aiMatrix4x4ToOfMatrix44(bone->mOffsetMatrix) * bn->getGlobalTransformMatrix(); boneMatrices[a] = aiMatrix4x4ToOfMatrix44(bone->mOffsetMatrix) * bn->getDerivedTransformMatrix(); modelMeshes[i].hasChanged = true; modelMeshes[i].validCache = false; } modelMeshes[i].animatedPos.assign(modelMeshes[i].animatedPos.size(),0); if(mesh->HasNormals()){ modelMeshes[i].animatedNorm.assign(modelMeshes[i].animatedNorm.size(),0); } // loop through all vertex weights of all bones for( size_t a = 0; a < mesh->mNumBones; ++a) { const aiBone* bone = mesh->mBones[a]; const aiMatrix4x4& posTrafo = ofMatrix4x4ToAiMatrix44(boneMatrices[a]); for( size_t b = 0; b < bone->mNumWeights; ++b) { const aiVertexWeight& weight = bone->mWeights[b]; size_t vertexId = weight.mVertexId; const aiVector3D& srcPos = mesh->mVertices[vertexId]; modelMeshes[i].animatedPos[vertexId] += weight.mWeight * (posTrafo * srcPos); } if(mesh->HasNormals()){ // 3x3 matrix, contains the bone matrix without the translation, only with rotation and possibly scaling aiMatrix3x3 normTrafo = aiMatrix3x3( posTrafo); for( size_t b = 0; b < bone->mNumWeights; ++b) { const aiVertexWeight& weight = bone->mWeights[b]; size_t vertexId = weight.mVertexId; const aiVector3D& srcNorm = mesh->mNormals[vertexId]; modelMeshes[i].animatedNorm[vertexId] += weight.mWeight * (normTrafo * srcNorm); } } } } updateGLResources(); }
//------------------------------------------- void ofxAssimpModelLoader::updateAnimation(unsigned int animationIndex, float currentTime){ const aiAnimation* mAnim = scene->mAnimations[animationIndex]; // calculate the transformations for each animation channel for( unsigned int a = 0; a < mAnim->mNumChannels; a++) { const aiNodeAnim* channel = mAnim->mChannels[a]; aiNode* targetNode = scene->mRootNode->FindNode(channel->mNodeName); // ******** Position ***** aiVector3D presentPosition( 0, 0, 0); if( channel->mNumPositionKeys > 0) { // Look for present frame number. Search from last position if time is after the last time, else from beginning // Should be much quicker than always looking from start for the average use case. unsigned int frame = 0;// (currentTime >= lastAnimationTime) ? lastFramePositionIndex : 0; while( frame < channel->mNumPositionKeys - 1) { if( currentTime < channel->mPositionKeys[frame+1].mTime) break; frame++; } // interpolate between this frame's value and next frame's value unsigned int nextFrame = (frame + 1) % channel->mNumPositionKeys; const aiVectorKey& key = channel->mPositionKeys[frame]; const aiVectorKey& nextKey = channel->mPositionKeys[nextFrame]; double diffTime = nextKey.mTime - key.mTime; if( diffTime < 0.0) diffTime += mAnim->mDuration; if( diffTime > 0) { float factor = float( (currentTime - key.mTime) / diffTime); presentPosition = key.mValue + (nextKey.mValue - key.mValue) * factor; } else { presentPosition = key.mValue; } } // ******** Rotation ********* aiQuaternion presentRotation( 1, 0, 0, 0); if( channel->mNumRotationKeys > 0) { unsigned int frame = 0;//(currentTime >= lastAnimationTime) ? lastFrameRotationIndex : 0; while( frame < channel->mNumRotationKeys - 1) { if( currentTime < channel->mRotationKeys[frame+1].mTime) break; frame++; } // interpolate between this frame's value and next frame's value unsigned int nextFrame = (frame + 1) % channel->mNumRotationKeys; const aiQuatKey& key = channel->mRotationKeys[frame]; const aiQuatKey& nextKey = channel->mRotationKeys[nextFrame]; double diffTime = nextKey.mTime - key.mTime; if( diffTime < 0.0) diffTime += mAnim->mDuration; if( diffTime > 0) { float factor = float( (currentTime - key.mTime) / diffTime); aiQuaternion::Interpolate( presentRotation, key.mValue, nextKey.mValue, factor); } else { presentRotation = key.mValue; } } // ******** Scaling ********** aiVector3D presentScaling( 1, 1, 1); if( channel->mNumScalingKeys > 0) { unsigned int frame = 0;//(currentTime >= lastAnimationTime) ? lastFrameScaleIndex : 0; while( frame < channel->mNumScalingKeys - 1) { if( currentTime < channel->mScalingKeys[frame+1].mTime) break; frame++; } // TODO: (thom) interpolation maybe? This time maybe even logarithmic, not linear presentScaling = channel->mScalingKeys[frame].mValue; } // build a transformation matrix from it //aiMatrix4x4& mat;// = mTransforms[a]; aiMatrix4x4 mat = aiMatrix4x4( presentRotation.GetMatrix()); mat.a1 *= presentScaling.x; mat.b1 *= presentScaling.x; mat.c1 *= presentScaling.x; mat.a2 *= presentScaling.y; mat.b2 *= presentScaling.y; mat.c2 *= presentScaling.y; mat.a3 *= presentScaling.z; mat.b3 *= presentScaling.z; mat.c3 *= presentScaling.z; mat.a4 = presentPosition.x; mat.b4 = presentPosition.y; mat.c4 = presentPosition.z; //mat.Transpose(); targetNode->mTransformation = mat; } lastAnimationTime = currentTime; // update mesh position for the animation for (unsigned int i = 0; i < modelMeshes.size(); ++i){ // current mesh we are introspecting const aiMesh* mesh = modelMeshes[i].mesh; // calculate bone matrices std::vector<aiMatrix4x4> boneMatrices( mesh->mNumBones); for( size_t a = 0; a < mesh->mNumBones; ++a) { const aiBone* bone = mesh->mBones[a]; // find the corresponding node by again looking recursively through the node hierarchy for the same name aiNode* node = scene->mRootNode->FindNode(bone->mName); // start with the mesh-to-bone matrix boneMatrices[a] = bone->mOffsetMatrix; // and now append all node transformations down the parent chain until we're back at mesh coordinates again const aiNode* tempNode = node; while( tempNode) { // check your matrix multiplication order here!!! boneMatrices[a] = tempNode->mTransformation * boneMatrices[a]; // boneMatrices[a] = boneMatrices[a] * tempNode->mTransformation; tempNode = tempNode->mParent; } modelMeshes[i].hasChanged = true; modelMeshes[i].validCache = false; } modelMeshes[i].animatedPos.assign(modelMeshes[i].animatedPos.size(),0); if(mesh->HasNormals()){ modelMeshes[i].animatedNorm.assign(modelMeshes[i].animatedNorm.size(),0); } // loop through all vertex weights of all bones for( size_t a = 0; a < mesh->mNumBones; ++a) { const aiBone* bone = mesh->mBones[a]; const aiMatrix4x4& posTrafo = boneMatrices[a]; for( size_t b = 0; b < bone->mNumWeights; ++b) { const aiVertexWeight& weight = bone->mWeights[b]; size_t vertexId = weight.mVertexId; const aiVector3D& srcPos = mesh->mVertices[vertexId]; modelMeshes[i].animatedPos[vertexId] += weight.mWeight * (posTrafo * srcPos); } if(mesh->HasNormals()){ // 3x3 matrix, contains the bone matrix without the translation, only with rotation and possibly scaling aiMatrix3x3 normTrafo = aiMatrix3x3( posTrafo); for( size_t b = 0; b < bone->mNumWeights; ++b) { const aiVertexWeight& weight = bone->mWeights[b]; size_t vertexId = weight.mVertexId; const aiVector3D& srcNorm = mesh->mNormals[vertexId]; modelMeshes[i].animatedNorm[vertexId] += weight.mWeight * (normTrafo * srcNorm); } } } } }
// http://sourceforge.net/projects/assimp/forums/forum/817654/topic/3880745 void ofxAssimpModelLoader::updateGLResources(){ // update mesh position for the animation for (unsigned int i = 0; i < modelMeshes.size(); ++i){ // current mesh we are introspecting const aiMesh* mesh = modelMeshes[i].mesh; // calculate bone matrices std::vector<aiMatrix4x4> boneMatrices( mesh->mNumBones); for( size_t a = 0; a < mesh->mNumBones; ++a) { const aiBone* bone = mesh->mBones[a]; // find the corresponding node by again looking recursively through the node hierarchy for the same name aiNode* node = scene->mRootNode->FindNode(bone->mName); // start with the mesh-to-bone matrix boneMatrices[a] = bone->mOffsetMatrix; // and now append all node transformations down the parent chain until we're back at mesh coordinates again const aiNode* tempNode = node; while( tempNode) { // check your matrix multiplication order here!!! boneMatrices[a] = tempNode->mTransformation * boneMatrices[a]; // boneMatrices[a] = boneMatrices[a] * tempNode->mTransformation; tempNode = tempNode->mParent; } } // all using the results from the previous code snippet std::vector<aiVector3D> resultPos( mesh->mNumVertices); std::vector<aiVector3D> resultNorm( mesh->mNumVertices); // loop through all vertex weights of all bones for( size_t a = 0; a < mesh->mNumBones; ++a) { const aiBone* bone = mesh->mBones[a]; const aiMatrix4x4& posTrafo = boneMatrices[a]; // 3x3 matrix, contains the bone matrix without the translation, only with rotation and possibly scaling aiMatrix3x3 normTrafo = aiMatrix3x3( posTrafo); for( size_t b = 0; b < bone->mNumWeights; ++b) { const aiVertexWeight& weight = bone->mWeights[b]; size_t vertexId = weight.mVertexId; const aiVector3D& srcPos = mesh->mVertices[vertexId]; const aiVector3D& srcNorm = mesh->mNormals[vertexId]; resultPos[vertexId] += weight.mWeight * (posTrafo * srcPos); resultNorm[vertexId] += weight.mWeight * (normTrafo * srcNorm); } } // now upload the result position and normal along with the other vertex attributes into a dynamic vertex buffer, VBO or whatever // get mesh helper for this mesh; ofxAssimpMeshHelper meshHelper = modelMeshes[i]; glBindBuffer(GL_ARRAY_BUFFER, meshHelper.vertexBuffer); aiVertex* verts = (aiVertex*)glMapBuffer(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); for (unsigned int x = 0; x < mesh->mNumVertices; ++x) { //verts->vPosition = mesh->mVertices[x]; verts->vPosition = resultPos[x]; if (NULL == mesh->mNormals) verts->vNormal = aiVector3D(0.0f,0.0f,0.0f); else verts->vNormal = resultNorm[x]; if (mesh->HasVertexColors(0)) { verts->dColorDiffuse = mesh->mColors[0][x]; } else verts->dColorDiffuse = aiColor4D(1.0, 1.0, 1.0, 1.0); // This varies slightly form Assimp View, we support the 3rd texture component. if (mesh->HasTextureCoords(0)) verts->vTextureUV = mesh->mTextureCoords[0][x]; else verts->vTextureUV = aiVector3D(0.5f,0.5f, 0.0f); // No longer in aiVertex VBO structure /* if (NULL == mesh->mTangents) { verts->vTangent = aiVector3D(0.0f,0.0f,0.0f); verts->vBitangent = aiVector3D(0.0f,0.0f,0.0f); } else { verts->vTangent = mesh->mTangents[x]; verts->vBitangent = mesh->mBitangents[x]; } if (mesh->HasTextureCoords(1)) verts->vTextureUV2 = mesh->mTextureCoords[1][x]; else verts->vTextureUV2 = aiVector3D(0.5f,0.5f, 0.0f); if( mesh->HasBones()){ unsigned char boneIndices[4] = { 0, 0, 0, 0 }; unsigned char boneWeights[4] = { 0, 0, 0, 0 }; ai_assert( weightsPerVertex[x].size() <= 4); for( unsigned int a = 0; a < weightsPerVertex[x].size(); a++){ boneIndices[a] = weightsPerVertex[x][a].mVertexId; boneWeights[a] = (unsigned char) (weightsPerVertex[x][a].mWeight * 255.0f); } memcpy( verts->mBoneIndices, boneIndices, sizeof( boneIndices)); memcpy( verts->mBoneWeights, boneWeights, sizeof( boneWeights)); } else{ // memset( verts->mBoneIndices, 0, sizeof( verts->mBoneIndices)); // memset( verts->mBoneWeights, 0, sizeof( verts->mBoneWeights)); } */ ++verts; } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); //invalidates verts glBindBuffer(GL_ARRAY_BUFFER, 0); } }
void Mesh::init_mesh(const aiScene* scene, const aiMesh* mesh, size_t index) { std::cout << "Loading mesh named '" << mesh->mName.C_Str() << "'" << std::endl; entries[index].material_index = mesh->mMaterialIndex; if (!mesh->HasNormals()) { std::cerr << "Mesh has no normals!" << std::endl; } else { if (mesh->mNumVertices > 0) std::cerr << "First normal:" << mesh->mNormals[0].x << "," << mesh->mNormals[0].y << "," << mesh->mNormals[0].z << std::endl; } // Create vectors to store the transformed position and normals; initialize them to the origin. std::vector<aiVector3D> final_pos(mesh->mNumVertices), final_normal(mesh->mNumVertices); for (size_t i = 0; i < mesh->mNumVertices; ++i) { final_pos[i] = final_normal[i] = aiVector3D(0.0, 0.0, 0.0); } std::vector<Vertex> vertices; std::vector<unsigned int> indices; const aiVector3D zero_3d(0.0, 0.0, 0.0); if (mesh->mNumBones) { std::vector<aiMatrix4x4> bone_matrices(mesh->mNumBones); // Calculate bone matrices. for (size_t i = 0; i < mesh->mNumBones; ++i) { const aiBone* bone = mesh->mBones[i]; bone_matrices[i] = bone->mOffsetMatrix; std::cout << "Bone '" << bone->mName.C_Str() << "' includes " << bone->mNumWeights << " vertices:" << std::endl; for (size_t j = 0; j < bone->mNumWeights; ++j) { std::cout << ' ' << bone->mWeights[j].mVertexId; } std::cout << std::endl; const aiNode* node = scene->mRootNode->FindNode(bone->mName.C_Str()); const aiNode* temp_node = node; while (temp_node != NULL) { bone_matrices[i] = temp_node->mTransformation * bone_matrices[i]; temp_node = temp_node->mParent; } } // Update vertex positions according to calculated matrices for (size_t i = 0; i < mesh->mNumBones; ++i) { const aiBone* bone = mesh->mBones[i]; aiMatrix3x3 normal_matrix = aiMatrix3x3(bone_matrices[i]); for (size_t j = 0; j < bone->mNumWeights; ++j) { const aiVertexWeight *vertex_weight = &(bone->mWeights[j]); size_t v = (size_t)(vertex_weight->mVertexId); float w = vertex_weight->mWeight; const aiVector3D *src_pos = &(mesh->mVertices[v]); const aiVector3D *src_normal = &(mesh->mNormals[v]); final_pos[v] += w * (bone_matrices[i] * (*src_pos)); final_normal[v] += w * (normal_matrix * (*src_normal)); } std::cout << "bone " << i << ":" << std::endl; std::cout << bone_matrices[i].a1 << ' ' << bone_matrices[i].a2 << ' ' << bone_matrices[i].a3 << ' ' << bone_matrices[i].a4 << std::endl; std::cout << bone_matrices[i].b1 << ' ' << bone_matrices[i].b2 << ' ' << bone_matrices[i].b3 << ' ' << bone_matrices[i].b4 << std::endl; std::cout << bone_matrices[i].c1 << ' ' << bone_matrices[i].c2 << ' ' << bone_matrices[i].c3 << ' ' << bone_matrices[i].c4 << std::endl; std::cout << bone_matrices[i].d1 << ' ' << bone_matrices[i].d2 << ' ' << bone_matrices[i].d3 << ' ' << bone_matrices[i].d4 << std::endl; } // initialize our dimension trackers. if (mesh->mNumVertices != 0) { min_extremities.x = final_pos[0].x; min_extremities.y = final_pos[0].y; min_extremities.z = final_pos[0].z; max_extremities = min_extremities; } // Add each updated vertex and calculate its extremities. for (size_t i = 0; i < mesh->mNumVertices; ++i) { const aiVector3D *diffuse_texture_coord = mesh->HasTextureCoords(0) ? &(mesh->mTextureCoords[0][i]) : &zero_3d; const aiVector3D *specular_texture_coord = mesh->HasTextureCoords(1) ? &(mesh->mTextureCoords[1][i]) : &zero_3d; // Find the extremities of this mesh so we can get a measurement for the object in object units. if (final_pos[i].x < min_extremities.x) min_extremities.x = final_pos[i].x; else if (final_pos[i].x > max_extremities.x) max_extremities.x = final_pos[i].x; if (final_pos[i].y < min_extremities.y) min_extremities.y = final_pos[i].y; else if (final_pos[i].y > max_extremities.y) max_extremities.y = final_pos[i].y; if (final_pos[i].z < min_extremities.z) min_extremities.z = final_pos[i].z; else if (final_pos[i].z > max_extremities.z) max_extremities.z = final_pos[i].z; Vertex vertex(glm::vec3(final_pos[i].x, final_pos[i].y, final_pos[i].z), glm::vec2(diffuse_texture_coord->x, diffuse_texture_coord->y), glm::vec2(specular_texture_coord->x, specular_texture_coord->y), glm::vec3(final_normal[i].x, final_normal[i].y, final_normal[i].z)); std::cout << "Adding vertex " << i << ": " << final_pos[i].x << "," << final_pos[i].y << "," << final_pos[i].z; std::cout << "\t" << final_normal[i].x << "," << final_normal[i].y << "," << final_normal[i].z << std::endl; std::cout << " was: " << mesh->mVertices[i].x << "," << mesh->mVertices[i].y << "," << mesh->mVertices[i].z << '\t'; std::cout << mesh->mNormals[i].x << "," << mesh->mNormals[i].y << "," << mesh->mNormals[i].z << std::endl; // Accumulate the centroid_ of the object. centroid_ += vertex.pos; vertices.push_back(vertex); } } else { for (unsigned int i = 0; i < mesh->mNumVertices; i++) { const aiVector3D* pos = &(mesh->mVertices[i]); const aiVector3D* normal = &(mesh->mNormals[i]); const aiVector3D* diffuse_texture_coord = mesh->HasTextureCoords(0) ? &(mesh->mTextureCoords[0][i]) : &zero_3d; const aiVector3D* specular_texture_coord = mesh->HasTextureCoords(1) ? &(mesh->mTextureCoords[1][i]) : &zero_3d; // Find the extremities of this mesh so we can get a measurement for the object in object units. if (pos->x < min_extremities.x) min_extremities.x = pos->x; else if (pos->x > max_extremities.x) max_extremities.x = pos->x; if (pos->y < min_extremities.y) min_extremities.y = pos->y; else if (pos->y > max_extremities.y) max_extremities.y = pos->y; if (pos->z < min_extremities.z) min_extremities.z = pos->z; else if (pos->z > max_extremities.z) max_extremities.z = pos->z; Vertex v(glm::vec3(pos->x, pos->y, pos->z), glm::vec2(diffuse_texture_coord->x, diffuse_texture_coord->y), glm::vec2(specular_texture_coord->x, specular_texture_coord->y), glm::vec3(normal->x, normal->y, normal->z)); // Accumulate the centroid_ of the object. centroid_ += v.pos; vertices.push_back(v); } } centroid_ /= mesh->mNumVertices; // Add vertices for each face for (size_t i = 0; i < mesh->mNumFaces; ++i) { const aiFace& face = mesh->mFaces[i]; if (face.mNumIndices != 3) { std::cerr << "Face has " << face.mNumIndices << " indices; skipping" << std::endl; continue; } indices.push_back(face.mIndices[0]); indices.push_back(face.mIndices[1]); indices.push_back(face.mIndices[2]); } // Create index buffer. entries[index].init(vertices, indices); }
void Model::recursiveRender(const aiNode* node){ LOGGER_ENTER("Model", "recursiveRender"); glPushMatrix(); int m = node->mNumMeshes; aiMatrix4x4 masterTransform = node->mTransformation; /* Iterate through the node's meshes */ for(int i = 0; i < m; i++){ aiMesh* mesh = model->mMeshes[node->mMeshes[i]]; Mesh m; if(gettingVertsAndNormals){ m.mNumVertices = mesh->mNumVertices; m.vertices = new glm::vec3[m.mNumVertices]; m.normals = new glm::vec3[m.mNumVertices]; m.numFaces = mesh->mNumFaces; m.faceVertexIndices = new int*[m.numFaces]; m.name = mesh->mName.C_Str(); } aiVector3D* vertices = mesh->mVertices; aiVector3D* normals = mesh->mNormals; /*** Calculate Skeleton Transformations and Resulting Vertex Trasformations ***/ if(mesh->HasBones()){ vertices = new aiVector3D[mesh->mNumVertices]; normals = new aiVector3D[mesh->mNumVertices]; for(unsigned int b = 0; b < mesh->mNumBones; b++){ aiMatrix4x4 boneMatrix; const aiBone* bone = mesh->mBones[b]; aiNode* boneNode = findNodeRecurse(model->mRootNode, bone->mName); boneMatrix = bone->mOffsetMatrix; const aiNode* tmpNode = boneNode; while(tmpNode){ boneMatrix = tmpNode->mTransformation * boneMatrix; tmpNode = tmpNode->mParent; } const aiMatrix4x4& posTransform = boneMatrix; const aiMatrix3x3 normalTransform = aiMatrix3x3(posTransform); for(unsigned int w = 0; w < bone->mNumWeights; w++){ const aiVertexWeight& weight = bone->mWeights[w]; unsigned int vertexID = weight.mVertexId; const aiVector3D& srcPos = mesh->mVertices[vertexID]; const aiVector3D& srcNormal = mesh->mNormals[vertexID]; vertices[vertexID] += weight.mWeight * (posTransform * srcPos); normals[vertexID] += weight.mWeight * (normalTransform * srcNormal); } } } /* Bind the texture if a diffuse texture exists */ aiMaterial* mat = model->mMaterials[mesh->mMaterialIndex]; int texIndex = 0; aiString texPath; if(AI_SUCCESS == mat->GetTexture(aiTextureType_DIFFUSE, texIndex, &texPath)) { unsigned int texId = textureIdMap[texPath.data]; glBindTexture(GL_TEXTURE_2D, texId); } aiString matName; mat->Get(AI_MATKEY_NAME,matName); aiColor3D matDiffuseColour(0,0,0); if(mat->Get(AI_MATKEY_COLOR_DIFFUSE,matDiffuseColour) == AI_SUCCESS){ float fMatDiffuseColour[] = {matDiffuseColour.r, matDiffuseColour.g, matDiffuseColour.b}; glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fMatDiffuseColour); } aiColor3D matSpecularColour(0,0,0); if(mat->Get(AI_MATKEY_COLOR_SPECULAR,matSpecularColour) == AI_SUCCESS){ float fMatSpecularColour[] = {matSpecularColour.r, matSpecularColour.g, matSpecularColour.b}; glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, fMatSpecularColour); } aiColor3D matAmbientColour(0,0,0); if(mat->Get(AI_MATKEY_COLOR_AMBIENT,matAmbientColour) == AI_SUCCESS){ float fMatAmbientColour[] = {matAmbientColour.r, matAmbientColour.g, matAmbientColour.b}; glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, fMatAmbientColour); } /* Draw Mesh Faces (Textures) */ aiVector3D* texCoords = mesh->mTextureCoords[0]; for(unsigned int j = 0; j < mesh->mNumFaces; j++){ unsigned int* indices = mesh->mFaces[j].mIndices; aiVector3D n1, n2, n3, v1, v2, v3; if(mesh->HasBones()){ n1 = normals[indices[0]]; n2 = normals[indices[1]]; n3 = normals[indices[2]]; v1 = vertices[indices[0]]; v2 = vertices[indices[1]]; v3 = vertices[indices[2]]; }else{ n1 = MODEL_ROT_MAT * (masterTransform * normals[indices[0]]); n2 = MODEL_ROT_MAT * (masterTransform * normals[indices[1]]); n3 = MODEL_ROT_MAT * (masterTransform * normals[indices[2]]); v1 = MODEL_ROT_MAT * (masterTransform * vertices[indices[0]]); v2 = MODEL_ROT_MAT * (masterTransform * vertices[indices[1]]); v3 = MODEL_ROT_MAT * (masterTransform * vertices[indices[2]]); } glm::vec3 tmpV1(v1.x,v1.y,v1.z); glm::vec3 tmpV2(v2.x,v2.y,v2.z); glm::vec3 tmpV3(v3.x,v3.y,v3.z); glm::vec3 faceNormal = glm::normalize(glm::cross(tmpV3 - tmpV2, tmpV1 - tmpV2)); if(gettingVertsAndNormals){ glm::vec3 tmpN1(n1.x,n1.y,n1.z); glm::vec3 tmpN2(n2.x,n2.y,n2.z); glm::vec3 tmpN3(n3.x,n3.y,n3.z); m.vertices[indices[0]] = tmpV1; m.vertices[indices[1]] = tmpV2; m.vertices[indices[2]] = tmpV3; m.normals[indices[0]] = faceNormal; m.normals[indices[1]] = faceNormal; m.normals[indices[2]] = faceNormal; m.faceVertexIndices[j] = new int[3]; m.faceVertexIndices[j][0] = indices[0]; m.faceVertexIndices[j][1] = indices[1]; m.faceVertexIndices[j][2] = indices[2]; meshesMap[matName.C_Str()] = m; }else{ glBegin(GL_POLYGON); if(mesh->HasTextureCoords(0)) glTexCoord2f(texCoords[indices[0]].x, 1 - texCoords[indices[0]].y); glNormal3f(faceNormal.x, faceNormal.y, faceNormal.z); glVertex3f(v1.x, v1.y, v1.z); if(mesh->HasTextureCoords(0)) glTexCoord2f(texCoords[indices[1]].x, 1 - texCoords[indices[1]].y); glVertex3f(v2.x, v2.y, v2.z); if(mesh->HasTextureCoords(0)) glTexCoord2f(texCoords[indices[2]].x, 1 - texCoords[indices[2]].y); glVertex3f(v3.x, v3.y, v3.z); glEnd(); } } /* Free the memory that was used for the animated vertices and normals */ if(mesh->HasBones()){ free(normals); free(vertices); } /* Remove any texture binding */ glBindTexture(GL_TEXTURE_2D, NULL); } /* Recurse Through Child Nodes */ for(unsigned int i = 0; i < node->mNumChildren; i++){ recursiveRender(node->mChildren[i]); } glPopMatrix(); LOGGER_EXIT; }
// Recursively traverses the assimp node hierarchy, accumulating // modeling transformations, and creating and transforming any meshes // found. Meshes comming from assimp can have associated surface // properties, so each mesh *copies* the current BRDF as a starting // point and modifies it from the assimp data structure. void recurseModelNodes(Scene* scene, const aiScene* aiscene, const aiNode* node, const aiMatrix4x4& parentTr, const int level) { // Print line with indentation to show structure of the model node hierarchy. for (int i=0; i<level; i++) printf("| "); printf("%s ", node->mName.data); // Accumulating transformations while traversing down the hierarchy. aiMatrix4x4 childTr = parentTr*node->mTransformation; aiMatrix3x3 normalTr = aiMatrix3x3(childTr); // Really should be inverse-transpose for full generality // Loop through this node's meshes for (unsigned int i=0; i<node->mNumMeshes; ++i) { aiMesh* aimesh = aiscene->mMeshes[node->mMeshes[i]]; printf("%d:%d ", aimesh->mNumVertices, aimesh->mNumFaces); // Extract this node's surface material. aiString texPath; aiMaterial* mtl = aiscene->mMaterials[aimesh->mMaterialIndex]; // Assimp can read material colors from the input files, but // it seems to invent colors of its own unpredictably so I // ignore them. Textures and texture coordinates seem to work // well. //aiColor3D diff (0.f,0.f,0.f); //aiColor3D spec (0.f,0.f,0.f); //float s; // if (AI_SUCCESS == mtl->Get(AI_MATKEY_COLOR_DIFFUSE, diff)) // scene->setKd(Vector3f(diff.r, diff.g, diff.b)); // if (AI_SUCCESS == mtl->Get(AI_MATKEY_COLOR_SPECULAR, spec)) // scene->setKs(Vector3f(spec.r, spec.g, spec.b)); // if (AI_SUCCESS == mtl->Get(AI_MATKEY_SHININESS, &s, NULL)) // scene->setAlpha(s); Material *material = new Material(*scene->currentMat); if (AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, 0, &texPath)) material->setTexture(texPath.C_Str()); // Arrays to hold all vertex and triangle data. MeshData* meshdata = new MeshData; // Loop through all vertices and record the // vertex/normal/texture/tangent data with the node's model // transformation applied. for (unsigned int t=0; t<aimesh->mNumVertices; ++t) { aiVector3D aipnt = childTr*aimesh->mVertices[t]; aiVector3D ainrm = aimesh->HasNormals() ? normalTr*aimesh->mNormals[t] : aiVector3D(0,0,1); aiVector3D aitex = aimesh->HasTextureCoords(0) ? aimesh->mTextureCoords[0][t] : aiVector3D(0,0,0); aiVector3D aitan = aimesh->HasTangentsAndBitangents() ? normalTr*aimesh->mTangents[t] : aiVector3D(1,0,0); meshdata->vertices.push_back(VertexData(Vector3f(aipnt.x, aipnt.y, aipnt.z), Vector3f(ainrm.x, ainrm.y, ainrm.z), Vector2f(aitex.x, aitex.y), Vector3f(aitan.x, aitan.y, aitan.z))); } // Loop through all faces, recording indices for (unsigned int t=0; t<aimesh->mNumFaces; ++t) { aiFace* aiface = &aimesh->mFaces[t]; meshdata->triangles.push_back(TriData(aiface->mIndices[0], aiface->mIndices[1], aiface->mIndices[2])); } meshdata->mat = material; scene->triangleMesh(meshdata); delete meshdata; } printf("\n"); // Recurse onto this node's children for (unsigned int i=0; i<node->mNumChildren; ++i) recurseModelNodes(scene, aiscene, node->mChildren[i], childTr, level+1); }