void Model_Impl::Load(CL_GraphicContext &gc, GraphicStore *gs, const char *filename) { generate_texture_coords = true; const struct aiScene* scene = aiImportFileExWithProperties(filename,aiProcessPreset_TargetRealtime_MaxQuality, NULL, gs->store); if (!scene) throw CL_Exception("Cannot load a model"); try { vbo_size = count_vertices(scene, scene->mRootNode); if (!vbo_size) throw CL_Exception("No vertices found in the model"); vbo_positions = CL_VertexArrayBuffer(gc, vbo_size * sizeof(CL_Vec3f), cl_usage_static_draw); vbo_normals = CL_VertexArrayBuffer(gc, vbo_size * sizeof(CL_Vec3f), cl_usage_static_draw); if (generate_texture_coords) vbo_texcoords = CL_VertexArrayBuffer(gc, vbo_size * sizeof(CL_Vec2f), cl_usage_static_draw); insert_vbo(0, scene, scene->mRootNode); }catch(...) { aiReleaseImport(scene); throw; } aiReleaseImport(scene); }
const aiScene* MeshShape::loadMesh(const std::string& _fileName) { aiPropertyStore* propertyStore = aiCreatePropertyStore(); // remove points and lines aiSetImportPropertyInteger(propertyStore, AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE); const aiScene* scene = aiImportFileExWithProperties(_fileName.c_str(), aiProcess_GenNormals | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_SortByPType | aiProcess_OptimizeMeshes, NULL, propertyStore); aiReleasePropertyStore(propertyStore); // Assimp rotates collada files such that the up-axis (specified in the // collada file) aligns with assimp's y-axis. Here we are reverting this // rotation. We are only catching files with the .dae file ending here. We // might miss files with an .xml file ending, which would need to be looked // into to figure out whether they are collada files. if (_fileName.length() >= 4 && _fileName.substr(_fileName.length() - 4, 4) == ".dae") { scene->mRootNode->mTransformation = aiMatrix4x4(); } scene = aiApplyPostProcessing(scene, aiProcess_PreTransformVertices); return scene; }
//------------------------------------------ bool ofxAssimpModelLoader::loadModel(string modelName, bool optimize){ file.open(modelName, ofFile::ReadOnly, true); // Since it may be a binary file we should read it in binary -Ed if(!file.exists()) { ofLogVerbose("ofxAssimpModelLoader") << "loadModel(): model does not exist: \"" << modelName << "\""; return false; } ofLogVerbose("ofxAssimpModelLoader") << "loadModel(): loading \"" << file.getFileName() << "\" from \"" << file.getEnclosingDirectory() << "\""; if(scene.get() != nullptr){ clear(); // we reset the shared_ptr explicitly here, to force the old // aiScene to be deleted **before** a new aiScene is created. scene.reset(); } // sets various properties & flags to a default preference unsigned int flags = initImportProperties(optimize); // loads scene from file scene = shared_ptr<const aiScene>(aiImportFileExWithProperties(file.getAbsolutePath().c_str(), flags, NULL, store.get()), aiReleaseImport); bool bOk = processScene(); return bOk; }
const aiScene* ShapeMesh::loadMesh(const string& fileName) { aiPropertyStore* propertyStore = aiCreatePropertyStore(); aiSetImportPropertyInteger(propertyStore, AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE ); // remove points and lines const aiScene* scene = aiImportFileExWithProperties(fileName.c_str(), aiProcess_GenNormals | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_SortByPType | aiProcess_PreTransformVertices | aiProcess_OptimizeMeshes, NULL, propertyStore); aiReleasePropertyStore(propertyStore); return scene; }
void Model_Impl::Load(GraphicContext &gc, GraphicStore *gs, const char *filename) { const struct aiScene* scene = aiImportFileExWithProperties(filename,aiProcessPreset_TargetRealtime_MaxQuality, NULL, gs->store); if (!scene) throw Exception("Cannot load a model"); try { vbo_size = count_vertices(scene, scene->mRootNode); if (!vbo_size) throw Exception("No vertices found in the model"); vbo_positions = VertexArrayVector<Vec3f>(gc, vbo_size); vbo_normals = VertexArrayVector<Vec3f>(gc, vbo_size); insert_vbo(gc, 0, scene, scene->mRootNode); }catch(...) { aiReleaseImport(scene); throw; } aiReleaseImport(scene); }
////////////////////////////////////////////////////////////////////////// // import BcBool ScnAnimationImport::import( const Json::Value& ) { #if PSY_IMPORT_PIPELINE if( Source_.empty() ) { PSY_LOG( "ERROR: Missing 'source' field.\n" ); return BcFalse; } CsResourceImporter::addDependency( Source_.c_str() ); auto PropertyStore = aiCreatePropertyStore(); aiLogStream AssimpLogger = { AssimpLogStream, (char*)this }; aiAttachLogStream( &AssimpLogger ); Scene_ = aiImportFileExWithProperties( Source_.c_str(), 0, nullptr, PropertyStore ); aiReleasePropertyStore( PropertyStore ); if( Scene_ != nullptr ) { PSY_LOG( "Found %u animations:\n", Scene_->mNumAnimations ); for( int Idx = 0; Idx < (int)Scene_->mNumAnimations; ++Idx ) { PSY_LOG( " - %s\n", Scene_->mAnimations[ Idx ]->mName.C_Str() ); } // Build animated nodes list. Need this to calculate relative transforms later. recursiveParseAnimatedNodes( Scene_->mRootNode, BcErrorCode ); // Pack down animation into useful internal format. BcAssert( Scene_->mNumAnimations == 1 ); for( BcU32 AnimationIdx = 0; AnimationIdx < 1; ++AnimationIdx ) { auto* Animation = Scene_->mAnimations[ AnimationIdx ]; BcF32 Rate = 1.0f; BcU32 Duration = static_cast< BcU32 >( Animation->mDuration / Rate ); // Setup data streams. ScnAnimationHeader Header; Header.NoofNodes_ = Animation->mNumChannels; Header.NoofPoses_ = Duration; Header.Flags_ = scnAF_DEFAULT; Header.Packing_ = scnAP_R16S16T16; // TODO: Make this configurable when we factor out into another class. HeaderStream_ << Header; // Animation node file data. ScnAnimationNodeFileData NodeFileData; for( BcU32 NodeIdx = 0; NodeIdx < Animation->mNumChannels; ++NodeIdx ) { auto* Channel = Animation->mChannels[ NodeIdx ]; NodeFileData.Name_ = CsResourceImporter::addString( Channel->mNodeName.C_Str() ); NodeStream_ << NodeFileData; } // Calculate output pose. for( BcF32 Time = 0.0f; Time <= Animation->mDuration; Time += Rate ) { ScnAnimationPoseFileData Pose; Pose.Time_ = Time / FrameRate_; Pose.KeyDataOffset_ = static_cast< BcU32 >( KeyStream_.dataSize() ); // Iterate over all node channels to generate keys. for( BcU32 ChannelIdx = 0; ChannelIdx < Animation->mNumChannels; ++ChannelIdx ) { auto* Channel = Animation->mChannels[ ChannelIdx ]; auto& AnimatedNode = findAnimatedNode( Channel->mNodeName.C_Str() ); aiVector3D OutPositionKey; aiVector3D OutScaleKey; aiQuaternion OutRotationKey; // Extract position. GetKeyNodeAnim( Channel->mPositionKeys, Channel->mNumPositionKeys, Time, BcTrue, OutPositionKey ); // Extract scale. GetKeyNodeAnim( Channel->mScalingKeys, Channel->mNumScalingKeys, Time, BcTrue, OutScaleKey ); // Extract rotation. GetKeyNodeAnim( Channel->mRotationKeys, Channel->mNumRotationKeys, Time, BcTrue, OutRotationKey ); // Combine key into transform. ScnAnimationTransform Transform; Transform.R_ = MaQuat( OutRotationKey.x, OutRotationKey.y, OutRotationKey.z, OutRotationKey.w ); Transform.S_ = MaVec3d( OutScaleKey.x, OutScaleKey.y, OutScaleKey.z ); Transform.T_ = MaVec3d( OutPositionKey.x, OutPositionKey.y, OutPositionKey.z ); // Store as local matrix. Transform.toMatrix( AnimatedNode.LocalTransform_ ); } // Calculate local node matrices relative to their parents. for( auto& AnimatedNode : AnimatedNodes_ ) { if( AnimatedNode.ParentIdx_ != BcErrorCode ) { auto& ParentAnimatedNode( AnimatedNodes_[ AnimatedNode.ParentIdx_ ] ); MaMat4d ParentLocal = ParentAnimatedNode.LocalTransform_; AnimatedNode.WorldTransform_ = ParentLocal * AnimatedNode.LocalTransform_; } else { AnimatedNode.WorldTransform_ = AnimatedNode.LocalTransform_; } } // Write out pose keys. ScnAnimationTransformKey_R16S16T16 OutKey; for( BcU32 ChannelIdx = 0; ChannelIdx < Animation->mNumChannels; ++ChannelIdx ) { auto* Channel = Animation->mChannels[ ChannelIdx ]; const auto& AnimatedNode = findAnimatedNode( Channel->mNodeName.C_Str() ); // Extract individual transform elements. ScnAnimationTransform Transform; Transform.fromMatrix( AnimatedNode.LocalTransform_ ); // Pack into output key. OutKey.pack( Transform.R_, Transform.S_, Transform.T_ ); KeyStream_ << OutKey; } // Final size + CRC. Pose.KeyDataSize_ = static_cast< BcU32 >( KeyStream_.dataSize() - Pose.KeyDataOffset_ ); Pose.CRC_ = BcHash::GenerateCRC32( 0, KeyStream_.pData() + Pose.KeyDataOffset_, Pose.KeyDataSize_ ); // Write out pose. PoseStream_ << Pose; } // Write out chunks. CsResourceImporter::addChunk( BcHash( "header" ), HeaderStream_.pData(), HeaderStream_.dataSize(), 16, csPCF_IN_PLACE ); CsResourceImporter::addChunk( BcHash( "nodes" ), NodeStream_.pData(), NodeStream_.dataSize() ); CsResourceImporter::addChunk( BcHash( "poses" ), PoseStream_.pData(), PoseStream_.dataSize() ); CsResourceImporter::addChunk( BcHash( "keys" ), KeyStream_.pData(), KeyStream_.dataSize() ); } aiReleaseImport( Scene_ ); Scene_ = nullptr; // return BcTrue; } #endif // PSY_IMPORT_PIPELINE return BcFalse; }
const aiScene* MeshShape::loadMesh( const std::string& _uri, const common::ResourceRetrieverPtr& _retriever) { // Remove points and lines from the import. aiPropertyStore* propertyStore = aiCreatePropertyStore(); aiSetImportPropertyInteger(propertyStore, AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_POINT | aiPrimitiveType_LINE ); // Wrap ResourceRetriever in an IOSystem from Assimp's C++ API. Then wrap // the IOSystem in an aiFileIO from Assimp's C API. Yes, this API is // completely ridiculous... AssimpInputResourceRetrieverAdaptor systemIO(_retriever); aiFileIO fileIO = createFileIO(&systemIO); // Import the file. const aiScene* scene = aiImportFileExWithProperties( _uri.c_str(), aiProcess_GenNormals | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_SortByPType | aiProcess_OptimizeMeshes, &fileIO, propertyStore ); // If succeeded, store the importer in the scene to keep it alive. This is // necessary because the importer owns the memory that it allocates. if(!scene) { dtwarn << "[MeshShape::loadMesh] Failed loading mesh '" << _uri << "'.\n"; return nullptr; } // Assimp rotates collada files such that the up-axis (specified in the // collada file) aligns with assimp's y-axis. Here we are reverting this // rotation. We are only catching files with the .dae file ending here. We // might miss files with an .xml file ending, which would need to be looked // into to figure out whether they are collada files. std::string extension; const size_t extensionIndex = _uri.find_last_of('.'); if(extensionIndex != std::string::npos) extension = _uri.substr(extensionIndex); std::transform(std::begin(extension), std::end(extension), std::begin(extension), ::tolower); if(extension == ".dae" || extension == ".zae") scene->mRootNode->mTransformation = aiMatrix4x4(); // Finally, pre-transform the vertices. We can't do this as part of the // import process, because we may have changed mTransformation above. scene = aiApplyPostProcessing(scene, aiProcess_PreTransformVertices); if(!scene) dtwarn << "[MeshShape::loadMesh] Failed pre-transforming vertices.\n"; return scene; }