void MeshLoaderSPM::readChunkAnimationSkeletal() { /* Read skeletal animation basics */ const io::stringc AnimName(File_->readStringData()); /* Add new skeletal animation */ SkeletalAnimation* Anim = gSharedObjects.SceneMngr->createAnimation<SkeletalAnimation>("SPM Animation"); AnimationSkeleton* Skeleton = Anim->createSkeleton(); /* Read animation joints */ const u32 JointCount = File_->readValue<u32>(); Joints_.resize(JointCount); for (u32 i = 0; i < JointCount; ++i) readChunkAnimationJoint(Joints_[i]); /* Build joint construction */ foreach (SJointSPM &Joint, Joints_) { /* Create joint object */ Joint.JointObject = Skeleton->createJoint( Transformation(Joint.Position, Joint.Rotation, Joint.Scale), Joint.Name ); /* Setup vertex weights */ std::vector<SVertexGroup> VertexGroups; VertexGroups.resize(Joint.VertexWeights.size()); u32 i = 0; foreach (const SVertexWeightSPM &Vertex, Joint.VertexWeights) { VertexGroups[i++] = SVertexGroup( CurMesh_, Vertex.Surface, Vertex.Index, Vertex.Weight ); } Joint.JointObject->setVertexGroups(VertexGroups); /* Setup keyframes */ foreach (const SKeyframeSPM &Keyframe, Joint.Keyframes) { Anim->addKeyframe( Joint.JointObject, Keyframe.Frame, Transformation(Keyframe.Position, Keyframe.Rotation, Keyframe.Scale) ); } }
bool GameLib::loadSkeletalAnimation(std::string filename, SkeletalAnimation& outAnimation) { Assimp::Importer importer; const aiScene* scene = importer.ReadFile(filename, aiProcess_ValidateDataStructure); if(scene == nullptr || scene->mNumAnimations == 0) return false; aiAnimation* animation = scene->mAnimations[0]; std::unordered_map<double, SkeletalPose> poses; std::hash<std::string> hash; for(unsigned int i = 0; i < animation->mNumChannels; i++) { aiNodeAnim* node = animation->mChannels[i]; std::string nodeName(node->mNodeName.C_Str()); unsigned int boneId = hash(nodeName); // load positions for(unsigned int j = 0; j < node->mNumPositionKeys; j++) { aiVectorKey key = node->mPositionKeys[j]; SkeletalPose::BonePosition existingPosition = poses[key.mTime].getBonePosition(boneId); existingPosition.position.x = key.mValue.x; existingPosition.position.y = key.mValue.y; existingPosition.position.z = key.mValue.z; poses[key.mTime].setBonePosition(boneId, existingPosition); } // load rotations for(unsigned int j = 0; j < node->mNumRotationKeys; j++) { aiQuatKey key = node->mRotationKeys[j]; SkeletalPose::BonePosition existingPosition = poses[key.mTime].getBonePosition(boneId); // calculate the angle from the quaternion float rad = std::acos(key.mValue.w); float sinRad = std::sin(rad); existingPosition.rotationAxis.x = key.mValue.x / sinRad; existingPosition.rotationAxis.y = key.mValue.y / sinRad; existingPosition.rotationAxis.z = key.mValue.z / sinRad; existingPosition.rotation = rad; poses[key.mTime].setBonePosition(boneId, existingPosition); } // load scalings for(unsigned int j = 0; j < node->mNumScalingKeys; j++) { aiVectorKey key = node->mScalingKeys[j]; SkeletalPose::BonePosition existingPosition = poses[key.mTime].getBonePosition(boneId); existingPosition.scale.x = key.mValue.x; existingPosition.scale.y = key.mValue.y; existingPosition.scale.z = key.mValue.z; poses[key.mTime].setBonePosition(boneId, existingPosition); } } // add poses to animation for(auto posePair : poses) { outAnimation.addPose((float)posePair.first, posePair.second); } return true; }
UNNAMESPACE_BEGIN /*============================================================================== Procedural API/functions. ==============================================================================*/ //------------------------------------------------------------------------------ //! int animationVM( VMState* vm ) { ProceduralAnimation* userData = (ProceduralAnimation*)VM::userData( vm ); SkeletalAnimation* anim = userData->animation(); // Only accept a table as argument. if( !VM::isTable( vm, 1 ) ) { StdErr << "Missing arguments to animation()." << nl; return 0; } // Read parameters. float rate; if( VM::get( vm, 1, "rate", rate ) ) anim->rate( rate ); Vec3f vel; if( VM::get( vm, 1, "velocity", vel ) ) anim->velocity( vel ); Vec3f offset; if( VM::get( vm, 1, "offset", offset ) ) anim->offset( offset ); bool cyclic; if( VM::get( vm, 1, "cyclic", cyclic ) ) anim->cyclic( cyclic ); uint type; if( VM::get( vm, 1, "type", type ) ) anim->type( type ); if( VM::get( vm, 1, "poses" ) ) { anim->reservePoses( VM::getTableSize( vm, -1 ) ); // Read all poses. for( int p = 1; VM::geti( vm, -1, p ); ++p ) { Reff ref = Reff::identity(); if( !VM::get( vm, -1, "p", ref.position() ) ) { ref.position( Vec3f::zero() ); } if( !VM::get( vm, -1, "q", ref.orientation() ) ) { ref.orientation( Quatf::identity() ); } RCP<SkeletalPose> pose = anim->addPose( ref ); pose->reserveBones( VM::getTableSize( vm, -1 ) ); // Read all bones positions in pose. for( int i = 1; VM::geti( vm, -1, i ); ++i ) { pose->addBone( VM::toQuatf( vm, -1 ) ); VM::pop( vm, 1 ); } VM::pop( vm, 1 ); } VM::pop( vm, 1 ); } anim->prepare(); // Fix some corner cases. anim->makeRelative(); return 0; }
void SkeletalMeshNode::Play(SkeletalAnimation& anim, bool loop) { assert(anim.CheckJoints(*m_jointList)); m_anim = &anim; m_anim->Play(loop); }