Example #1
0
const aiScene* MeshShape::loadMesh(const std::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_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;
}
Example #2
0
//////////////////////////////////////////////////////////////////////////
// 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;	
}
Example #3
0
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;
}