AnimationPath路径动画实现详解:
一、关联类图展示
二、实现详解
首先我们通过调用createAnimationPath方法来创建动画路径,即:通过起点、终点以及之间的时间步长来进行插值来保证动画的一个流畅度,然后将这些时间和点保存到一个map容器中(_timeControlPointMap)。
osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime)
{// set up the animation path osg::AnimationPath* animationPath = new osg::AnimationPath;animationPath->setLoopMode(osg::AnimationPath::LOOP);int numSamples = 40;float yaw = 0.0f;float yaw_delta = 2.0f*osg::PI/((float)numSamples-1.0f);float roll = osg::inDegrees(30.0f);double time=0.0f;double time_delta = looptime/(double)numSamples;for(int i=0;i<numSamples;++i){osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius,0.0f));osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0))*osg::Quat(-(yaw+osg::inDegrees(90.0f)),osg::Vec3(0.0,0.0,1.0)));animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));yaw += yaw_delta;time += time_delta;}return animationPath;
}
然后创建一个模型节点,即:要让它跟着我们指定的路径变化的节点。学过opengl或者游戏开发的都清楚,要想让一个点从一个位置变化到另一个位置,最好是通过矩阵来改变它的位置,所以我们需要把这个模型节点添加到矩阵中来动态更新它的位置,这样才能有一个连续的动画效果。
osg::Node* createMovingModel(const osg::Vec3& center, float radius)
{float animationLength = 10.0f;osg::AnimationPath* animationPath = createAnimationPath(center,radius,animationLength);osg::Group* model = new osg::Group;/// 通过读取模型来创建节点osg::Node* glider = osgDB::readNodeFile("glider.osgt");if (glider){const osg::BoundingSphere& bs = glider->getBound();float size = radius/bs.radius()*0.3f;osg::MatrixTransform* positioned = new osg::MatrixTransform;positioned->setDataVariance(osg::Object::STATIC);positioned->setMatrix(osg::Matrix::translate(-bs.center())*osg::Matrix::scale(size,size,size)*osg::Matrix::rotate(osg::inDegrees(-90.0f),0.0f,0.0f,1.0f));positioned->addChild(glider);osg::PositionAttitudeTransform* xform = new osg::PositionAttitudeTransform; xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0,1.0));xform->addChild(positioned);model->addChild(xform);}/// 通过读取模型来创建节点osg::Node* cessna = osgDB::readNodeFile("cessna.osgt");if (cessna){const osg::BoundingSphere& bs = cessna->getBound();float size = radius/bs.radius()*0.3f;osg::MatrixTransform* positioned = new osg::MatrixTransform;positioned->setDataVariance(osg::Object::STATIC);positioned->setMatrix(osg::Matrix::translate(-bs.center())*osg::Matrix::scale(size,size,size)*osg::Matrix::rotate(osg::inDegrees(180.0f),0.0f,0.0f,1.0f));positioned->addChild(cessna);osg::MatrixTransform* xform = new osg::MatrixTransform;xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,2.0));xform->addChild(positioned);model->addChild(xform);}return model;
}
其次创建矩阵来改变模型节点的位置、旋转角度和缩放比。即:可以创建用于给变位置和旋转角的PositionAttitudeTransform对象,也可以创建MatrixTransform对象来对模型节点做更多的变换操作,最后将这些矩阵都添加到Group中来统一管理。
/// 创建位置属性变换对象,通过设置更新回调来动态改变节点的位置和旋转角osg::PositionAttitudeTransform* xform = new osg::PositionAttitudeTransform; xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0,1.0));xform->addChild(positioned);model->addChild(xform);/// 创建变换矩阵对象,通过设置更新回调来动态改变节点的位置和旋转角osg::MatrixTransform* xform = new osg::MatrixTransform;xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,2.0));xform->addChild(positioned);model->addChild(xform);}
最后创建更新回调(AnimationPathCallback),通过为矩阵设置更新回调来动态更新节点变化,至于更新回调怎么调用这就需要大家看看渲染一帧到底做了什么操作,推介大家看(OSG_王锐《最长的一帧》)。AnimationPathCallback类中有两个方法需要注意:operator()和update(in node:Node&)方法,在updata方法中通过AnimationPathCallbackVisitor访问器来改变节点的矩阵。
/// 创建位置属性变换对象,通过设置更新回调来动态改变节点的位置和旋转角osg::PositionAttitudeTransform* xform = new osg::PositionAttitudeTransform; /// 设置路径动画更新回调xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0,1.0));xform->addChild(positioned);model->addChild(xform);/// 创建变换矩阵对象,通过设置更新回调来动态改变节点的位置和旋转角osg::MatrixTransform* xform = new osg::MatrixTransform;/// 设置路径动画更新回调xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,2.0));xform->addChild(positioned);model->addChild(xform);










