void setKeyframe( osgDB::Input& fr, int ch, double time, osgAnimation::Vec3KeyframeContainer* posKey, osgAnimation::QuatKeyframeContainer* rotKey ) { if ( ch&0x07 && posKey ) // Position keyframe { float keyValue[3] = { 0.0f }; if ( ch&0x01 ) fr.readSequence( keyValue[0] ); if ( ch&0x02 ) fr.readSequence( keyValue[1] ); if ( ch&0x04 ) fr.readSequence( keyValue[2] ); osg::Vec3 vec( keyValue[0], keyValue[1], keyValue[2] ); posKey->push_back( osgAnimation::Vec3Keyframe(time, vec) ); } if ( ch&0x38 && rotKey ) // Rotation keyframe { float keyValue[3] = { 0.0f }; if ( ch&0x08 ) fr.readSequence( keyValue[2] ); if ( ch&0x10 ) fr.readSequence( keyValue[0] ); if ( ch&0x20 ) fr.readSequence( keyValue[1] ); // Note that BVH data need to concatenate the rotating matrices as Y*X*Z // So we should not create Quat directly from input values, which makes a wrong X*Y*Z osg::Matrix rotMat = osg::Matrix::rotate(osg::DegreesToRadians(keyValue[1]), osg::Vec3(0.0,1.0,0.0)) * osg::Matrix::rotate(osg::DegreesToRadians(keyValue[0]), osg::Vec3(1.0,0.0,0.0)) * osg::Matrix::rotate(osg::DegreesToRadians(keyValue[2]), osg::Vec3(0.0,0.0,1.0)); osg::Quat quat = rotMat.getRotate(); rotKey->push_back( osgAnimation::QuatKeyframe(time, quat) ); } }
void buildHierarchy( osgDB::Input& fr, int level, osgAnimation::Bone* parent ) { bool isRecognized = false; if ( !parent ) return; if ( fr.matchSequence("OFFSET %f %f %f") ) { isRecognized = true; ++fr; osg::Vec3 offset; if ( fr.readSequence(offset) ) { // Process OFFSET section parent->setBindMatrixInBoneSpace( osg::Matrix::translate(offset) ); if ( _drawingFlag && parent->getNumParents() && level>0 ) parent->getParent(0)->addChild( createRefGeometry(offset, 0.5).get() ); } } if ( fr.matchSequence("CHANNELS %i") ) { isRecognized = true; // Process CHANNELS section int noChannels; fr[1].getInt( noChannels ); fr += 2; for ( int i=0; i<noChannels; ++i ) { // Process each channel std::string channelName; fr.readSequence( channelName ); alterChannel( channelName, _joints.back().second ); } } if ( fr.matchSequence("End Site {") ) { isRecognized = true; fr += 3; if ( fr.matchSequence("OFFSET %f %f %f") ) { ++fr; osg::Vec3 offsetEndSite; if ( fr.readSequence(offsetEndSite) ) { // Process End Site section osg::ref_ptr<osgAnimation::Bone> bone = new osgAnimation::Bone( parent->getName()+"End" ); bone->setBindMatrixInBoneSpace( osg::Matrix::translate(offsetEndSite) ); bone->setDataVariance( osg::Object::DYNAMIC ); parent->addChild( bone.get() ); if ( _drawingFlag ) parent->addChild( createRefGeometry(offsetEndSite, 0.5).get() ); } } fr.advanceOverCurrentFieldOrBlock(); } if ( fr.matchSequence("ROOT %w {") || fr.matchSequence("JOINT %w {") ) { isRecognized = true; // Process JOINT section osg::ref_ptr<osgAnimation::Bone> bone = new osgAnimation::Bone( fr[1].getStr() ); bone->setDefaultUpdateCallback(); bone->setDataVariance( osg::Object::DYNAMIC ); parent->addChild( bone.get() ); _joints.push_back( JointNode(bone, 0) ); int entry = fr[1].getNoNestedBrackets(); fr += 3; while ( !fr.eof() && fr[0].getNoNestedBrackets()>entry ) buildHierarchy( fr, entry, bone.get() ); fr.advanceOverCurrentFieldOrBlock(); } if ( !isRecognized ) { osg::notify(osg::WARN) << "BVH Reader: Unrecognized symbol " << fr[0].getStr() << ". Ignore current field or block." << std::endl; fr.advanceOverCurrentFieldOrBlock(); } }
void buildMotion( osgDB::Input& fr, osgAnimation::Animation* anim ) { int i=0, frames=0; float frameTime=0.033f; if ( !fr.readSequence("Frames:", frames) ) { osg::notify(osg::WARN) << "BVH Reader: Frame number setting not found, but an unexpected " << fr[0].getStr() << ". Set to 1." << std::endl; } ++fr; if ( !fr.readSequence("Time:", frameTime) ) { osg::notify(osg::WARN) << "BVH Reader: Frame time setting not found, but an unexpected " << fr[0].getStr() << ". Set to 0.033 (30FPS)." << std::endl; } // Each joint has a position animating channel and an euler animating channel std::vector< osg::ref_ptr<osgAnimation::Vec3LinearChannel> > posChannels; std::vector< osg::ref_ptr<osgAnimation::QuatSphericalLinearChannel> > rotChannels; for ( JointList::iterator itr=_joints.begin(); itr!=_joints.end(); ++itr ) { std::string name = itr->first->getName(); osg::ref_ptr<osgAnimation::Vec3KeyframeContainer> posKey = new osgAnimation::Vec3KeyframeContainer; osg::ref_ptr<osgAnimation::Vec3LinearSampler> posSampler = new osgAnimation::Vec3LinearSampler; osg::ref_ptr<osgAnimation::Vec3LinearChannel> posChannel = new osgAnimation::Vec3LinearChannel( posSampler.get() ); posSampler->setKeyframeContainer( posKey.get() ); posChannel->setName( "position" ); posChannel->setTargetName( name ); osg::ref_ptr<osgAnimation::QuatKeyframeContainer> rotKey = new osgAnimation::QuatKeyframeContainer; osg::ref_ptr<osgAnimation::QuatSphericalLinearSampler> rotSampler = new osgAnimation::QuatSphericalLinearSampler; osg::ref_ptr<osgAnimation::QuatSphericalLinearChannel> rotChannel = new osgAnimation::QuatSphericalLinearChannel( rotSampler.get() ); rotSampler->setKeyframeContainer( rotKey.get() ); rotChannel->setName( "quaternion" ); rotChannel->setTargetName( name ); posChannels.push_back( posChannel ); rotChannels.push_back( rotChannel ); } // Obtain motion data from the stream while ( !fr.eof() && i<frames ) { for ( unsigned int n=0; n<_joints.size(); ++n ) { osgAnimation::Vec3LinearChannel* posChannel = posChannels[n].get(); osgAnimation::QuatSphericalLinearChannel* rotChannel = rotChannels[n].get(); setKeyframe( fr, _joints[n].second, frameTime*(double)i, dynamic_cast<osgAnimation::Vec3KeyframeContainer*>(posChannel->getSampler()->getKeyframeContainer()), dynamic_cast<osgAnimation::QuatKeyframeContainer*>(rotChannel->getSampler()->getKeyframeContainer()) ); } i++; } // Add valid channels to the animate object for ( unsigned int n=0; n<_joints.size(); ++n ) { if ( posChannels[n]->getOrCreateSampler()->getOrCreateKeyframeContainer()->size()>0 ) anim->addChannel( posChannels[n].get() ); if ( rotChannels[n]->getOrCreateSampler()->getOrCreateKeyframeContainer()->size()>0 ) anim->addChannel( rotChannels[n].get() ); } }