osg animate 操作

osgAnimation几乎可以模拟所有的运动,在模拟的过程中,使用插值来计算当前的状态(也就是t)。interpolation介绍:http://sol.gfxile.net/interpolation/

osg使用的easeMotion原理介绍: http://robertpenner.com/easing/

其中几个常用的插值函数QuadMothion(二次插值),CubicMotion(三次插值), QuartMotion(四次插值), BounceMotion,ElasticMotion,SineMotion(正弦插值), BackMotion, CircMotion(循环插值), ExpoMotion(指数插值)。

理论上讲,图形学里变化有平移变换、旋转变换、剪切变换。在不改变顶点个数及组合方式的基础上,有顶点变化,纹理变化等。所以设计实现任意animation是完全可行的。OSG以这几个方面为基础实现了animation的基本操作。不过目前来看,这个设计还比较初级,使用起来比较麻烦,需要比较了解才可以使用。

下面是我了解到的osg的animation架构,草图一张来解释下:


最后给一个例子,osg大牛王锐的

/* -*-c++-*- OpenSceneGraph Cookbook
 * Chapter 5 Recipe 1
 * Author: Wang Rui <wangray84 at gmail dot com>
*/

#include <osg/ShapeDrawable>
#include <osg/MatrixTransform>
#include <osgAnimation/BasicAnimationManager>
#include <osgAnimation/UpdateMatrixTransform>
#include <osgAnimation/StackedRotateAxisElement>
#include <osgViewer/Viewer>
#include <algorithm>

#include "CommonFunctions"

osg::Node* createWall()
{
    osg::ref_ptr<osg::ShapeDrawable> wallLeft =
        new osg::ShapeDrawable( new osg::Box(osg::Vec3(-5.5f, 0.0f, 0.0f), 10.0f, 0.3f, 10.0f) );
    osg::ref_ptr<osg::ShapeDrawable> wallRight =
        new osg::ShapeDrawable( new osg::Box(osg::Vec3(10.5f, 0.0f, 0.0f), 10.0f, 0.3f, 10.0f) );
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    geode->addDrawable( wallLeft.get() );
    geode->addDrawable( wallRight.get() );
    return geode.release();
}

osg::MatrixTransform* createDoor()
{
    osg::ref_ptr<osg::ShapeDrawable> doorShape =
        new osg::ShapeDrawable( new osg::Box(osg::Vec3(2.5f, 0.0f, 0.0f), 6.0f, 0.2f, 10.0f) );
    doorShape->setColor( osg::Vec4(1.0f, 1.0f, 0.8f, 1.0f) );
    
    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
    geode->addDrawable( doorShape.get() );
    
    osg::ref_ptr<osg::MatrixTransform> trans = new osg::MatrixTransform;
    trans->addChild( geode.get() );
    return trans.release();
}

void generateDoorKeyframes( osgAnimation::FloatLinearChannel* ch, bool closed )
{
    osgAnimation::FloatKeyframeContainer* kfs = ch->getOrCreateSampler()->getOrCreateKeyframeContainer();
    kfs->clear();
    if ( closed )
    {
        kfs->push_back( osgAnimation::FloatKeyframe(0.0, 0.0f) );
        kfs->push_back( osgAnimation::FloatKeyframe(1.0, osg::PI_2) );
    }
    else
    {
        kfs->push_back( osgAnimation::FloatKeyframe(0.0, osg::PI_2) );
        kfs->push_back( osgAnimation::FloatKeyframe(1.0, 0.0f) );
    }
}

class OpenDoorHandler : public osgCookBook::PickHandler
{
public:
    OpenDoorHandler() : _closed(true) {}
    
    virtual void doUserOperations( osgUtil::LineSegmentIntersector::Intersection& result )
    {
        osg::NodePath::iterator itr = std::find(
            result.nodePath.begin(), result.nodePath.end(), _door.get() );
        if ( itr!=result.nodePath.end() )
        {
            if ( _manager->isPlaying(_animation.get()) )
                return;
            
            osgAnimation::FloatLinearChannel* ch = dynamic_cast<osgAnimation::FloatLinearChannel*>(
                _animation->getChannels().front().get() );
            if ( ch )
            {
                generateDoorKeyframes( ch, _closed );
                _closed = !_closed;
            }
            _manager->playAnimation( _animation.get() );
        }
    }
    
    osg::observer_ptr<osgAnimation::BasicAnimationManager> _manager;
    osg::observer_ptr<osgAnimation::Animation> _animation;
    osg::observer_ptr<osg::MatrixTransform> _door;
    bool _closed;
};

int main( int argc, char** argv )
{
    // Create the animation callback
    osg::ref_ptr<osgAnimation::FloatLinearChannel> ch = new osgAnimation::FloatLinearChannel;
    ch->setName( "euler" );
    ch->setTargetName( "DoorAnimCallback" );
    generateDoorKeyframes( ch.get(), true );
    
    osg::ref_ptr<osgAnimation::Animation> animation = new osgAnimation::Animation;
    animation->setPlayMode( osgAnimation::Animation::ONCE );
    animation->addChannel( ch.get() );
    
    osg::ref_ptr<osgAnimation::UpdateMatrixTransform> updater =
        new osgAnimation::UpdateMatrixTransform("DoorAnimCallback");
    updater->getStackedTransforms().push_back(
        new osgAnimation::StackedRotateAxisElement("euler", osg::Z_AXIS, 0.0) );
    
    osg::ref_ptr<osgAnimation::BasicAnimationManager> manager = new osgAnimation::BasicAnimationManager;
    manager->registerAnimation( animation.get() );
    
    // Create the scene graph
    osg::MatrixTransform* animDoor = createDoor();
    animDoor->setUpdateCallback( updater.get() );
    
    osg::ref_ptr<osg::Group> root = new osg::Group;
    root->addChild( createWall() );
    root->addChild( animDoor );
    root->setUpdateCallback( manager.get() );
    
    osg::ref_ptr<OpenDoorHandler> handler = new OpenDoorHandler;
    handler->_manager = manager.get();
    handler->_animation = animation.get();
    handler->_door = animDoor;
    
    osgViewer::Viewer viewer;
    viewer.addEventHandler( handler.get() );
    viewer.setSceneData( root.get() );
    return viewer.run();
}



你可能感兴趣的:(animation,OSG)