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; }
GraphicStore::~GraphicStore() { if (store) { aiReleasePropertyStore(store); aiDetachAllLogStreams(); } }
GraphicStore::~GraphicStore() { #if defined(I_LOVE_ASSIMP_AND_PRECOMPILED_IT) if (store) { aiReleasePropertyStore(store); aiDetachAllLogStreams(); } #endif }
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; }
//------------------------------------------- bool ofxAssimpModelLoader::loadModel(ofBuffer & buffer, bool optimize, const char * extension){ normalizeFactor = ofGetWidth() / 2.0; if(scene != NULL){ clear(); } aiPropertyStore* propStore = aiCreatePropertyStore(); // only ever give us triangles. aiSetImportPropertyInteger(propStore, AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT ); aiSetImportPropertyInteger(propStore, AI_CONFIG_PP_PTV_NORMALIZE, true); // aiProcess_FlipUVs is for VAR code. Not needed otherwise. Not sure why. unsigned int flags = aiProcessPreset_TargetRealtime_MaxQuality | aiProcess_Triangulate | aiProcess_FlipUVs; if(optimize) flags |= aiProcess_ImproveCacheLocality | aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes | aiProcess_JoinIdenticalVertices | aiProcess_RemoveRedundantMaterials; scene = aiImportFileFromMemory(buffer.getBinaryBuffer(), (unsigned int)buffer.size(), flags, extension); aiReleasePropertyStore(propStore); if(scene){ calculateDimensions(); loadGLResources(); update(); if(getAnimationCount()) ofLog(OF_LOG_VERBOSE, "scene has animations"); else { ofLog(OF_LOG_VERBOSE, "no animations"); } return true; }else{ ofLog(OF_LOG_ERROR,string("ofxAssimpModelLoader: ") + aiGetErrorString()); return false; } }
////////////////////////////////////////////////////////////////////////// // 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; }