//------------------------------------------- void ofxAssimpModelLoader::getBoundingBoxForNode(const ofxAssimpMeshHelper & mesh, aiVector3D* min, aiVector3D* max){ if (!hasAnimations()){ for (size_t i=0; i<mesh.mesh->mNumVertices; i++){ auto vertex = mesh.mesh->mVertices[i]; auto tmp = ofVec3f(vertex.x,vertex.y,vertex.z) * mesh.matrix; min->x = MIN(min->x,tmp.x); min->y = MIN(min->y,tmp.y); min->z = MIN(min->z,tmp.z); max->x = MAX(max->x,tmp.x); max->y = MAX(max->y,tmp.y); max->z = MAX(max->z,tmp.z); } } else { for (auto & animPos: mesh.animatedPos){ auto tmp = ofVec3f(animPos.x,animPos.y,animPos.z) * mesh.matrix; min->x = MIN(min->x,tmp.x); min->y = MIN(min->y,tmp.y); min->z = MIN(min->z,tmp.z); max->x = MAX(max->x,tmp.x); max->y = MAX(max->y,tmp.y); max->z = MAX(max->z,tmp.z); } } }
// DEPRECATED. float ofxAssimpModelLoader::getDuration(int animationIndex) { if(!hasAnimations()) { return 0; } animationIndex = ofClamp(animationIndex, 0, getAnimationCount() - 1); float duration = animations[animationIndex].getDurationInSeconds(); return duration; }
// DEPRECATED. void ofxAssimpModelLoader::setTime(float time) { if(!hasAnimations()) { return; } setAnimation(currentAnimation); // call this again to clamp animation index, in case the model is reloaded. ofxAssimpAnimation & animation = animations[currentAnimation]; animation.setPosition(time); update(); }
// DEPRECATED. void ofxAssimpModelLoader::setNormalizedTime(float time) { if(!hasAnimations()) { return; } setAnimation(currentAnimation); // call this again to clamp animation index, in case the model is reloaded. ofxAssimpAnimation & animation = animations[currentAnimation]; float realT = ofMap(time, 0.0, 1.0, 0.0, animation.getDurationInSeconds(), false); setTime(realT); }
//------------------------------------------- update. void ofxAssimpModelLoader::update() { updateAnimations(); updateMeshes(scene->mRootNode, ofMatrix4x4()); if(hasAnimations() == false) { return; } updateBones(); updateGLResources(); }
void AnimationExporter::exportAnimations(Scene *sce) { if (hasAnimations(sce)) { this->scene = sce; openLibrary(); forEachObjectInExportSet(sce, *this, this->export_settings->export_set); closeLibrary(); } }
void AnimationExporter::exportAnimations(Scene *sce) { if(hasAnimations(sce)) { this->scene = sce; openLibrary(); forEachObjectInScene(sce, *this); closeLibrary(); } }
bool AnimationExporter::exportAnimations(Scene *sce) { bool has_animations = hasAnimations(sce); if (has_animations) { this->scene = sce; openLibrary(); forEachObjectInExportSet(sce, *this, this->export_settings->export_set); closeLibrary(); } return has_animations; }
void ofxAssimpModelLoader::updateGLResources(){ // now upload the result position and normal along with the other vertex attributes into a dynamic vertex buffer, VBO or whatever for (unsigned int i = 0; i < modelMeshes.size(); ++i){ if(modelMeshes[i].hasChanged){ const aiMesh* mesh = modelMeshes[i].mesh; if(hasAnimations()){ modelMeshes[i].vbo.updateVertexData(&modelMeshes[i].animatedPos[0].x,mesh->mNumVertices); if(mesh->HasNormals()){ modelMeshes[i].vbo.updateNormalData(&modelMeshes[i].animatedNorm[0].x,mesh->mNumVertices); } } modelMeshes[i].hasChanged = false; } } }
//------------------------------------------- ofMesh ofxAssimpModelLoader::getCurrentAnimatedMesh(string name){ for(int i=0; i<(int)modelMeshes.size(); i++){ if(string(modelMeshes[i].mesh->mName.data)==name){ if(!modelMeshes[i].validCache){ modelMeshes[i].cachedMesh.clearVertices(); modelMeshes[i].cachedMesh.clearNormals(); if(hasAnimations()){ modelMeshes[i].cachedMesh.addVertices(aiVecVecToOfVecVec(modelMeshes[i].animatedPos)); modelMeshes[i].cachedMesh.addNormals(aiVecVecToOfVecVec(modelMeshes[i].animatedNorm)); } modelMeshes[i].validCache = true; } return modelMeshes[i].cachedMesh; } } ofLogError("ofxAssimpModelLoader") << "getCurrentAnimatedMesh(): couldn't find mesh: \"" + name << "\""; return ofMesh(); }
// DEPRECATED. void ofxAssimpModelLoader::setAnimation(int animationIndex) { if(!hasAnimations()) { return; } currentAnimation = ofClamp(animationIndex, 0, getAnimationCount() - 1); }
void ofxAssimpModelLoader::updateBones() { if (!hasAnimations()){ return; } // 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 ofxAssimpModelLoader::loadGLResources(){ ofLogVerbose("ofxAssimpModelLoader") << "loadGLResources(): starting"; // create new mesh helpers for each mesh, will populate their data later. modelMeshes.resize(scene->mNumMeshes,ofxAssimpMeshHelper()); // create OpenGL buffers and populate them based on each meshes pertinant info. for (unsigned int i = 0; i < scene->mNumMeshes; ++i){ ofLogVerbose("ofxAssimpModelLoader") << "loadGLResources(): loading mesh " << i; // current mesh we are introspecting aiMesh* mesh = scene->mMeshes[i]; // the current meshHelper we will be populating data into. ofxAssimpMeshHelper & meshHelper = modelMeshes[i]; //ofxAssimpMeshHelper meshHelper; //meshHelper.texture = NULL; // Handle material info aiMaterial* mtl = scene->mMaterials[mesh->mMaterialIndex]; aiColor4D dcolor, scolor, acolor, ecolor; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &dcolor)){ meshHelper.material.setDiffuseColor(aiColorToOfColor(dcolor)); } if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &scolor)){ meshHelper.material.setSpecularColor(aiColorToOfColor(scolor)); } if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &acolor)){ meshHelper.material.setAmbientColor(aiColorToOfColor(acolor)); } if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &ecolor)){ meshHelper.material.setEmissiveColor(aiColorToOfColor(ecolor)); } float shininess; if(AI_SUCCESS == aiGetMaterialFloat(mtl, AI_MATKEY_SHININESS, &shininess)){ meshHelper.material.setShininess(shininess); } int blendMode; if(AI_SUCCESS == aiGetMaterialInteger(mtl, AI_MATKEY_BLEND_FUNC, &blendMode)){ if(blendMode==aiBlendMode_Default){ meshHelper.blendMode=OF_BLENDMODE_ALPHA; }else{ meshHelper.blendMode=OF_BLENDMODE_ADD; } } // Culling unsigned int max = 1; int two_sided; if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided) meshHelper.twoSided = true; else meshHelper.twoSided = false; // Load Textures int texIndex = 0; aiString texPath; // TODO: handle other aiTextureTypes if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, texIndex, &texPath)){ ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource(): loading image from \"" << texPath.data << "\""; string modelFolder = file.getEnclosingDirectory(); string relTexPath = ofFilePath::getEnclosingDirectory(texPath.data,false); string texFile = ofFilePath::getFileName(texPath.data); string realPath = ofFilePath::join(ofFilePath::join(modelFolder, relTexPath), texFile); if(ofFile::doesFileExist(realPath) == false) { ofLogError("ofxAssimpModelLoader") << "loadGLResource(): texture doesn't exist: \"" << file.getFileName() + "\" in \"" << realPath << "\""; } ofxAssimpTexture assimpTexture; bool bTextureAlreadyExists = false; for(int j=0; j<textures.size(); j++) { assimpTexture = textures[j]; if(assimpTexture.getTexturePath() == realPath) { bTextureAlreadyExists = true; break; } } if(bTextureAlreadyExists) { meshHelper.assimpTexture = assimpTexture; ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource(): texture already loaded: \"" << file.getFileName() + "\" from \"" << realPath << "\""; } else { ofTexture texture; bool bTextureLoadedOk = ofLoadImage(texture, realPath); if(bTextureLoadedOk) { textures.push_back(ofxAssimpTexture(texture, realPath)); assimpTexture = textures.back(); meshHelper.assimpTexture = assimpTexture; ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource(): texture loaded, dimensions: " << texture.getWidth() << "x" << texture.getHeight(); } else { ofLogError("ofxAssimpModelLoader") << "loadGLResource(): couldn't load texture: \"" << file.getFileName() + "\" from \"" << realPath << "\""; } } } meshHelper.mesh = mesh; aiMeshToOfMesh(mesh, meshHelper.cachedMesh, &meshHelper); meshHelper.cachedMesh.setMode(OF_PRIMITIVE_TRIANGLES); meshHelper.validCache = true; meshHelper.hasChanged = false; int numOfAnimations = scene->mNumAnimations; for (int i = 0; i<numOfAnimations; i++) { aiAnimation * animation = scene->mAnimations[i]; animations.push_back(ofxAssimpAnimation(scene, animation)); } if(hasAnimations()){ meshHelper.animatedPos.resize(mesh->mNumVertices); if(mesh->HasNormals()){ meshHelper.animatedNorm.resize(mesh->mNumVertices); } } int usage; if(getAnimationCount()){ #ifndef TARGET_OPENGLES if(!ofIsGLProgrammableRenderer()){ usage = GL_STATIC_DRAW; }else{ usage = GL_STREAM_DRAW; } #else usage = GL_DYNAMIC_DRAW; #endif }else{ usage = GL_STATIC_DRAW; } meshHelper.vbo.setVertexData(&mesh->mVertices[0].x,3,mesh->mNumVertices,usage,sizeof(aiVector3D)); if(mesh->HasVertexColors(0)){ meshHelper.vbo.setColorData(&mesh->mColors[0][0].r,mesh->mNumVertices,GL_STATIC_DRAW,sizeof(aiColor4D)); } if(mesh->HasNormals()){ meshHelper.vbo.setNormalData(&mesh->mNormals[0].x,mesh->mNumVertices,usage,sizeof(aiVector3D)); } if (meshHelper.cachedMesh.hasTexCoords()){ meshHelper.vbo.setTexCoordData(meshHelper.cachedMesh.getTexCoordsPointer()[0].getPtr(),mesh->mNumVertices,GL_STATIC_DRAW,sizeof(ofVec2f)); } meshHelper.indices.resize(mesh->mNumFaces * 3); int j=0; for (unsigned int x = 0; x < mesh->mNumFaces; ++x){ for (unsigned int a = 0; a < mesh->mFaces[x].mNumIndices; ++a){ meshHelper.indices[j++]=mesh->mFaces[x].mIndices[a]; } } meshHelper.vbo.setIndexData(&meshHelper.indices[0],meshHelper.indices.size(),GL_STATIC_DRAW); //modelMeshes.push_back(meshHelper); } ofLogVerbose("ofxAssimpModelLoader") << "loadGLResource(): finished"; }