1. 程式人生 > >OSG動畫庫Animation解析(二)

OSG動畫庫Animation解析(二)

在前文中討論到osgAnimation中的Target物件應該和場景的更新回撥有一些關係,本文接著前面繼續討論。

在前面的程式碼中,使用自己編寫的更新回撥類RotateCallback,osgAnimation根據動畫的內容和方式的不同,提供了幾種動畫的更新回撥類,分別是UpdateMatrixTransform和UpdateMorph(用來描述位置變化的動畫回撥)、UpdateMaterial(材質變化的動畫回撥)

1. UpdateMatrixTransform

在之前的RotateCallback中,把它設定為一個場景節點osg::MatrixTransform的更新回撥,這個也是UpdateMatrixTransform也是這樣一個類,它繼承與osg::NodeVisitor,的實現的operator方法如下:

void UpdateMatrixTransform::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
    if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
    {
        osg::MatrixTransform* matrixTransform = dynamic_cast<osg::MatrixTransform*>(node);
        if (matrixTransform)
        {
            //
here we would prefer to have a flag inside transform stack in order to avoid update and a dirty state in matrixTransform if it's not require. _transforms.update(); const osg::Matrix& matrix = _transforms.getMatrix(); matrixTransform->setMatrix(matrix); } } traverse(node,nv); }

程式碼的實現和之前寫的RotateCallback大同小異,不同之處在於旋轉矩陣matrix的計算方式,RotateCallback使用Target去獲取,而真實的計算過程在插值器中(通過Animation獲取Channel再獲取Sampler最後獲取到插值器,計算結果)。UpdateMatrixTransform矩陣的計算則是通過一個_transforms的陣列得到,它是一個StackedTransformElement的陣列。

按照之前的設想,場景需要的關鍵幀的值從Target獲得,在UpdateMatrixTransform應該也遵守這條規則,事實上確實是這樣,StackedTransformElement提供了操作Target的一些介面

    class  StackedTransformElement : public osg::Object
    {
    public:
        virtual void applyToMatrix(osg::Matrix& matrix) const = 0;
        virtual Target* getOrCreateTarget() {return 0;}
        virtual Target* getTarget() {return 0;}
        virtual const Target* getTarget() const {return 0;}
    };

根據動畫的型別,派生出許多不同型別的StackedTransformElement子類,主要包括:
StackedElement
與RotateCallback對應的應該是這裡的StackedRotateAxisElement

    class OSGANIMATION_EXPORT StackedRotateAxisElement : public StackedTransformElement
    {
    public:
        META_Object(osgAnimation, StackedRotateAxisElement);

        StackedRotateAxisElement();
        StackedRotateAxisElement(const StackedRotateAxisElement&, const osg::CopyOp&);
        StackedRotateAxisElement(const std::string& name, const osg::Vec3& axis, double angle);
        StackedRotateAxisElement(const osg::Vec3& axis, double angle);

        void applyToMatrix(osg::Matrix& matrix) const;
        osg::Matrix getAsMatrix() const;
        bool isIdentity() const { return (_angle == 0); }
        void update(float t = 0.0);

        const osg::Vec3& getAxis() const;
        double getAngle() const;
        void setAxis(const osg::Vec3&);
        void setAngle(double);

        virtual Target* getOrCreateTarget();
        virtual Target* getTarget() {return _target.get();}
        virtual const Target* getTarget() const {return _target.get();}

    protected:
        osg::Vec3 _axis;
        double _angle;
        osg::ref_ptr<FloatTarget> _target;
    };

這些派生類都要實現基類中的抽象函式applyToMatrix,這個函式起到真正的作用,StackedRotateAxisElement的實現如下:

void StackedRotateAxisElement::applyToMatrix(osg::Matrix& matrix) const 
{    
    matrix.preMultRotate(osg::Quat(_angle, _axis)); 
}

傳入的matrix會在原來的基礎上進行一次旋轉。

在引入了UpdateMatrixTransform之後,改造之前的程式,使用這個回撥代替RotateCallback,程式碼如下:


int main()
{
    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
    osg::ref_ptr<osg::Node> cowNode = osgDB::readNodeFile("cow.osg");

    osg::ref_ptr<osg::MatrixTransform> root = new osg::MatrixTransform;
    root->addChild(cowNode);

    osgAnimation::DoubleKeyframe keyframe1(0.0, 0.0);
    osgAnimation::DoubleKeyframe keyframe2(10.0, osg::PI * 2);

    osg::ref_ptr<osgAnimation::DoubleKeyframeContainer> keyframeContainer = new osgAnimation::DoubleKeyframeContainer();
    keyframeContainer->push_back(keyframe1);
    keyframeContainer->push_back(keyframe2);
    osg::ref_ptr<osgAnimation::DoubleLinearSampler> sampler = new osgAnimation::DoubleLinearSampler();
    sampler->setKeyframeContainer(keyframeContainer.get());
    osg::ref_ptr<osgAnimation::DoubleLinearChannel> channel = new osgAnimation::DoubleLinearChannel();
    channel->setSampler(sampler.get());

    osg::ref_ptr<osgAnimation::Animation> animation = new osgAnimation::Animation();
    animation->addChannel(channel.get());

    osg::ref_ptr<osgAnimation::UpdateMatrixTransform> umt = new osgAnimation::UpdateMatrixTransform();
    osg::ref_ptr<osgAnimation::StackedRotateAxisElement>    srae = new osgAnimation::StackedRotateAxisElement();
    srae->setAxis(osg::Z_AXIS);
    srae->setAngle(0.0);
    umt->getStackedTransforms().push_back(srae);
    root->addUpdateCallback(umt);

    viewer->setUpViewInWindow(200, 200, 800, 600);
    viewer->setSceneData(root);
    return viewer->run();
}

編譯執行之後,發現場景中模型並沒有變化,這是為什麼呢?仔細看一下發現osgAnimation::Animation類和UpdateMatrixTransform之間根本沒有任何關聯,也就是說真正作插值工作的Animation並沒有把中間幀的值傳給UpdateMatrixTransform,更具體來說是沒有把Animation插值的結果傳遞給StackedRotateAxisElement中的Target,也就是說需要把StackedRotateAxisElement中的Target和osgAnimation::Animation “連結”起來,這正是UpdateMatrixTransform這個類除了呼叫operator()之外的另一個作用。

2. 連結Animation與NodeCallback

通過檢視UpdateMatrixTransform的繼承關係
Inherits

在AnimationUpdateCallbackBase中定義的兩個連結純虛擬函式:

    class AnimationUpdateCallbackBase : public virtual osg::Object
    {
    public:
        virtual bool link(Channel* channel) = 0;
        virtual int link(Animation* animation) = 0;
    };

在AnimationUpdateCallback中實現了virtual int link(Animation* animation) = 0;,實現方式是將Animation中的每一個頻道分別呼叫link,剩下的工作就是在派生類中完成bool link(Channel* channel),UpdateMatrixTransform的實現:

bool UpdateMatrixTransform::link(osgAnimation::Channel* channel)
{
    const std::string& channelName = channel->getName();

    // check if we can link a StackedTransformElement to the current Channel
    for (StackedTransform::iterator it = _transforms.begin(); it != _transforms.end(); ++it)
    {
        StackedTransformElement* element = it->get();
        if (element && !element->getName().empty() && channelName == element->getName())
        {
            Target* target = element->getOrCreateTarget();
            if (target && channel->setTarget(target))
                return true;
        }
    }

    OSG_INFO << "UpdateMatrixTransform::link Channel " << channel->getName() << " does not contain a symbolic name that can be linked to a StackedTransformElement." << std::endl;

    return false;
}

這段程式碼非常的關鍵, 在上一篇文章(OSG動畫庫Animation解析(一))的結尾提到了,從Channel中強行獲取Target並捕獲Target儲存的中間幀的值,再設定給RotateCallback的方式非常的不自然,這個工作不應該是讓開發者去做,osgAnimation內部應該處理了,這段程式碼就解釋了osgAnimation是怎麼做的

從程式碼實現中瞭解到,Target的產生是由StackedTransformElement來負責的,將產生好的Target傳遞給Channel,從Channel中捕獲關鍵幀計算的結果,捕獲到的結果不需要開發者手動設定到UpdateMatrixTransform這個Callback中,在UpdateMatrixTransform的opeator()函式中通過

  _transforms.update();
  const osg::Matrix& matrix = _transforms.getMatrix();
  matrixTransform->setMatrix(matrix);

獲取到並且設定給呼叫Callback的節點了(也就是場景中的MatrixTransform),從而改變了模型的位置和姿態。至此整個Animation眾多的類如何協作起來共同驅動場景更新形成動畫的過程已經解釋清楚了。

另外注意設定Target給Channel的過程中,通過_transforms找到對應的StackedTransformElement和Channel關聯使用的是channel的名稱,也就是說在連結的時候需要設定Channel的名稱和StackedRotateAxisElement的名稱一樣,否則不能正確的將StackedRotateAxisElement產生的Target傳遞給Channel,從而使得整個資料傳遞鏈失敗。

瞭解了上面的原理,修改上面的程式,修改程式碼如下:

int main()
{
    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
    osg::ref_ptr<osg::Node> cowNode = osgDB::readNodeFile("cow.osg");

    osg::ref_ptr<osg::MatrixTransform> root = new osg::MatrixTransform;
    root->addChild(cowNode);

    osgAnimation::DoubleKeyframe keyframe1(0.0, 0.0);
    osgAnimation::DoubleKeyframe keyframe2(10.0, osg::PI * 2);

    osg::ref_ptr<osgAnimation::DoubleKeyframeContainer> keyframeContainer = new osgAnimation::DoubleKeyframeContainer();
    keyframeContainer->push_back(keyframe1);
    keyframeContainer->push_back(keyframe2);
    osg::ref_ptr<osgAnimation::DoubleLinearSampler> sampler = new osgAnimation::DoubleLinearSampler();
    sampler->setKeyframeContainer(keyframeContainer.get());
    osg::ref_ptr<osgAnimation::DoubleLinearChannel> channel = new osgAnimation::DoubleLinearChannel();
    channel->setSampler(sampler.get());
    channel->setName("rotateAroundZAxis");

    osg::ref_ptr<osgAnimation::Animation> animation = new osgAnimation::Animation();
    animation->addChannel(channel.get());

    osg::ref_ptr<osgAnimation::UpdateMatrixTransform> umt = new osgAnimation::UpdateMatrixTransform();
    osg::ref_ptr<osgAnimation::StackedRotateAxisElement>    srae = new osgAnimation::StackedRotateAxisElement();
    srae->setAxis(osg::Z_AXIS);
    srae->setName("rotateAroundZAxis");
    umt->getStackedTransforms().push_back(srae);
    umt->link(channel.get());
    root->addUpdateCallback(umt);


    viewer->setUpViewInWindow(200, 200, 800, 600);
    viewer->setSceneData(root);
    return viewer->run();
}

執行程式碼,發現仍然沒有動畫效果。問題出在哪兒呢?通過修改的程式碼,已經將動畫執行需要的整個流程打通了(Animation中的Channel通過Channel內部的Sampler取樣得到中間幀的值,由UpdateMatrixTransform中的StackedRotateAxisElement陣列產生的Targets傳遞給Channel接受中間幀的值,並設定給UpdateMatrixTransform的宿主(場景中的樹結構MatrixTransform))。與之前的程式碼對比發現:Animation的update方法並沒有被呼叫,也就是說“萬事俱備,只欠東風”,這裡沒有驅動動畫執行的更新時間點,Animation中Channel的update方法沒有被呼叫,根本沒有辦法產生中間幀的值。

既然沒有驅動動畫執行的方式,可以“製造”一個驅動方式,可以通過在MatrixTransform的上層節點中新增一個回撥,在這個回撥中呼叫Animation的update方法。【需要注意的是,這個節點一定要在MatrixTransform之上,因為osg會從樹的頂端一直往下遍歷,執行每一個節點的UpdateCallback,只有讓先於MatrixTransform進行變化,才能讓和MatrixTransform繫結的這個UpdatematrixTransform獲得計算的插值結果,從而改變MatrixTransform】,修改的程式碼如下:

class DummyDriverNodeCallback : public osg::NodeCallback
{
public:
    DummyDriverNodeCallback(osgAnimation::Animation *dls)
    {
        _startTick = osg::Timer::instance()->tick();
        _animation = dls;
    }

    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
    {
        double currentTick = osg::Timer::instance()->tick();
        double elaspedTime = osg::Timer::instance()->delta_s(_startTick, currentTick);

        _animation->resetTargets();
        _animation->setPlayMode(osgAnimation::Animation::LOOP);
        _animation->update(elaspedTime);
        _animation->setWeight(1.0);

        traverse(node, nv);
    }

protected:

    osg::ref_ptr<osgAnimation::Animation>    _animation;
    double                                   _startTick;
};

int main()
{
    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
    osg::ref_ptr<osg::Node> cowNode = osgDB::readNodeFile("cow.osg");

    osg::ref_ptr<osg::MatrixTransform> root = new osg::MatrixTransform;
    root->addChild(cowNode);

    osgAnimation::DoubleKeyframe keyframe1(0.0, 0.0);
    osgAnimation::DoubleKeyframe keyframe2(10.0, osg::PI * 2);

    osg::ref_ptr<osgAnimation::DoubleKeyframeContainer> keyframeContainer = new osgAnimation::DoubleKeyframeContainer();
    keyframeContainer->push_back(keyframe1);
    keyframeContainer->push_back(keyframe2);
    osg::ref_ptr<osgAnimation::DoubleLinearSampler> sampler = new osgAnimation::DoubleLinearSampler();
    sampler->setKeyframeContainer(keyframeContainer.get());
    osg::ref_ptr<osgAnimation::DoubleLinearChannel> channel = new osgAnimation::DoubleLinearChannel();
    channel->setSampler(sampler.get());
    channel->setName("rotateAroundZAxis");
    channel->setTargetName("updateMatrixCallback");

    osg::ref_ptr<osgAnimation::Animation> animation = new osgAnimation::Animation();
    animation->addChannel(channel);

    osg::ref_ptr<osgAnimation::UpdateMatrixTransform> umt = new osgAnimation::UpdateMatrixTransform();
    umt->setName("updateMatrixCallback");
    osgAnimation::StackedRotateAxisElement* srae = new osgAnimation::StackedRotateAxisElement("rotateAroundZAxis", osg::Z_AXIS, 0.0);
    umt->getStackedTransforms().push_back(srae);
    osg::ref_ptr<osgAnimation::AnimationUpdateCallbackBase> base = umt;
    base->link(animation);

    root->addUpdateCallback(umt);

    osg::ref_ptr<osg::Group> dummyDriverGroup = new osg::Group;
    dummyDriverGroup->addUpdateCallback(new DummyDriverNodeCallback(animation));
    dummyDriverGroup->addChild(root);

    viewer->setUpViewInWindow(200, 200, 800, 600);
    viewer->setSceneData(dummyDriverGroup);
    return viewer->run();
}

執行之後發現會出現崩潰的情況,除錯之後發現在StackedRotateAxisElement中使用的是Target的Target變數,在連結到Channel時(Channel的setTarget函式),Channel使用的是DoubleTarget,強制轉換之後會失敗,導致Channel的Target是空值。修改辦法要麼我們寫一個StackedRotateAxisElement的派生類使用DoubleTarget作為成員變數,或者為了簡便,把之前的Double型別都修改成float型別,修改之後程式碼如下:

class DummyDriverNodeCallback : public osg::NodeCallback
{
public:
    DummyDriverNodeCallback(osgAnimation::Animation *dls)
    {
        _startTick = osg::Timer::instance()->tick();
        _animation = dls;
    }

    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
    {
        double currentTick = osg::Timer::instance()->tick();
        double elaspedTime = osg::Timer::instance()->delta_s(_startTick, currentTick);

        _animation->resetTargets();
        _animation->setPlayMode(osgAnimation::Animation::LOOP);
        _animation->update(elaspedTime);
        _animation->setWeight(1.0);

        traverse(node, nv);
    }

protected:

    osg::ref_ptr<osgAnimation::Animation>    _animation;
    double                                   _startTick;
};



int main()
{
    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
    osg::ref_ptr<osg::Node> cowNode = osgDB::readNodeFile("cow.osg");

    osg::ref_ptr<osg::MatrixTransform> root = new osg::MatrixTransform;
    root->addChild(cowNode);

    osgAnimation::FloatKeyframe keyframe1(0.0, 0.0);
    osgAnimation::FloatKeyframe keyframe2(10.0, osg::PI * 2);

    osg::ref_ptr<osgAnimation::FloatKeyframeContainer> keyframeContainer = new osgAnimation::FloatKeyframeContainer();
    keyframeContainer->push_back(keyframe1);
    keyframeContainer->push_back(keyframe2);
    osg::ref_ptr<osgAnimation::FloatLinearSampler> sampler = new osgAnimation::FloatLinearSampler();
    sampler->setKeyframeContainer(keyframeContainer.get());
    osg::ref_ptr<osgAnimation::FloatLinearChannel> channel = new osgAnimation::FloatLinearChannel();
    channel->setSampler(sampler.get());
    channel->setName("rotateAroundZAxis");
    channel->setTargetName("updateMatrixCallback");

    osg::ref_ptr<osgAnimation::Animation> animation = new osgAnimation::Animation();
    animation->addChannel(channel);

    osg::ref_ptr<osgAnimation::UpdateMatrixTransform> umt = new osgAnimation::UpdateMatrixTransform();
    umt->setName("updateMatrixCallback");
    osgAnimation::StackedRotateAxisElement* srae = new osgAnimation::StackedRotateAxisElement("rotateAroundZAxis", osg::Z_AXIS, 0.0);
    umt->getStackedTransforms().push_back(srae);
    osg::ref_ptr<osgAnimation::AnimationUpdateCallbackBase> base = umt;
    base->link(animation);

    root->addUpdateCallback(umt);

    osg::ref_ptr<osg::Group> dummyDriverGroup = new osg::Group;
    dummyDriverGroup->addUpdateCallback(new DummyDriverNodeCallback(animation));
    dummyDriverGroup->addChild(root);

    viewer->setUpViewInWindow(200, 200, 800, 600);
    viewer->setSceneData(dummyDriverGroup);
    return viewer->run();
}

編譯執行程式,一切正常了。在編碼中有兩個地方需要注意一下:

  1. UpdateMatrixTransform在與Animation進行連線的時候,會和需要設定UpdateMatrixTransform的名稱與Animation中Channel的Target的名稱一樣
  2. UpdateMatrixTransform中的StackedTransform陣列中每一個物件的名稱(StackedTransformElement)必須和Channel的名稱一樣,這樣才能把StackedTransformElement new出來的Target傳給對應的Channel
  3. 還有一個小地方提一下:UpdateMatrixTransform不能直接link一個Animation,需要把它轉換到父類的指標才能呼叫父類中的方法(由於使用了虛繼承的原因)

3. 動畫的管理

通過前面的程式碼,基本上把整個Animation的過程都講到了。上面的程式碼使用了DummyDriverNodeCallback來驅動動畫,同時代碼中手動連結了UpdateMatrix和Animation,在OSG中提供了動畫的管理類來幫助開發者做這樣的事情,原理當然和前面手動實現的是一樣的,只不過OSG把這些實現整理的更加結構化一點,方便使用。

3.1 AnimationManagerBase

這個類定義了管理Animation的基類,它是一個NodeCallback,提供了連線動畫中Target到Animation的工作。同時提供了新增Animation和刪除Animation的功能,管理一個Animation的陣列。除此之外它提供的功能和上面寫的DummyDriverNodeCallback一樣,驅動動畫開始,它的operator()實現如下:

void AnimationManagerBase::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
    if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
    {
        if (needToLink())
        {
            /** manager need to link, it means that an animation has been added
                so we need to relink all item animated with all animations.
                We apply the linker visitor on the manager node to affect
                all its children.
                But it should not be done here, it should be done in the
                update of AnimationManager
            */
            link(node);
        }
        const osg::FrameStamp* fs = nv->getFrameStamp();
        update(fs->getSimulationTime());
    }
    traverse(node,nv);
}

可以看到,如果場景需要動畫進行連結(說明有新動畫被新增),那麼連線一次,之後就呼叫update函式來開始驅動動畫了,這個類的update函式是一個純虛擬函式,需要子類實現。它的連線是使用LinkVisitor來進行遍歷場景的。

3.2 LinkVisitor

遍歷場景中所有的節點,如果發現這個節點存在UpdateCallback,並且這個Callback可以轉換成AnimationUpdateCallbackBase(比如前面提到的UpdateMatrixTransform),那麼就會執行link的操作,將動畫和這個UpdateMatrixTransform連線起來。(具體的步驟和上面程式碼中的一樣)。

3.3 BasicAnimationManager

這個類在AnimationManagerBase的基礎上添加了動畫管理的功能,可以播放動畫和暫定動畫的播放,其實很簡單。把當前啟用動畫的物件儲存到一個數組就可以了,因為它是驅動動畫播放的,只讓啟用的動畫的update函式呼叫,就可以起到這樣的效果,需要停止某個動畫時,把它從列表中刪掉就可以了。它繼承自AnimationManagerBase,重寫了純虛的方法update
,實現如下:

void BasicAnimationManager::update (double time)
{
    _lastUpdate = time;

    for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); ++it)
        (*it).get()->reset();

    for( AnimationLayers::reverse_iterator iterAnim = _animationsPlaying.rbegin(); iterAnim != _animationsPlaying.rend(); ++iterAnim )
    {
        std::vector<int> toremove;
        int priority = iterAnim->first;
        AnimationList& list = iterAnim->second;
        for (unsigned int i = 0; i < list.size(); i++)
        {
            if (! list[i]->update(time, priority))
            {
                toremove.push_back(i);
            } else
            {
            }
        }

        while (!toremove.empty())
        {
            list.erase(list.begin() + toremove.back());
            toremove.pop_back();
        }
    }
}

這個函式每一幀把所有的動畫執行一遍,會把執行動畫收集起來,在執行過後刪除掉這個臨時的陣列【這裡我個人認為是否是除錯的程式碼沒有刪掉,收集執行的動畫,之後刪掉好像沒有什麼意義,不知道大家怎麼看?
】,動畫是按priority進行排序播放的(動畫在新增播放的時候給了一個優先順序,按優先順序儲存在一個map中,這些都非常好理解)。既然引入了osgAnimation的動畫管理,那麼繼續調整上面的程式:


int main()
{
    osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
    osg::ref_ptr<osg::Node> cowNode = osgDB::readNodeFile("cow.osg");

    osg::ref_ptr<osg::MatrixTransform> root = new osg::MatrixTransform;
    root->addChild(cowNode);

    osgAnimation::FloatKeyframe keyframe1(0.0, 0.0);
    osgAnimation::FloatKeyframe keyframe2(10.0, osg::PI * 2);

    osg::ref_ptr<osgAnimation::FloatKeyframeContainer> keyframeContainer = new osgAnimation::FloatKeyframeContainer();
    keyframeContainer->push_back(keyframe1);
    keyframeContainer->push_back(keyframe2);
    osg::ref_ptr<osgAnimation::FloatLinearSampler> sampler = new osgAnimation::FloatLinearSampler();
    sampler->setKeyframeContainer(keyframeContainer.get());
    osg::ref_ptr<osgAnimation::FloatLinearChannel> channel = new osgAnimation::FloatLinearChannel();
    channel->setSampler(sampler.get());
    channel->setName("rotateAroundZAxis");
    channel->setTargetName("updateMatrixCallback");

    osg::ref_ptr<osgAnimation::Animation> animation = new osgAnimation::Animation();
    animation->addChannel(channel);

    osg::ref_ptr<osgAnimation::UpdateMatrixTransform> umt = new osgAnimation::UpdateMatrixTransform();
    umt->setName("updateMatrixCallback");
    osgAnimation::StackedRotateAxisElement* srae = new osgAnimation::StackedRotateAxisElement("rotateAroundZAxis", osg::Z_AXIS, 0.0);
    umt->getStackedTransforms().push_back(srae);
    root->addUpdateCallback(umt);

    osg::ref_ptr<osgAnimation::BasicAnimationManager>   bam = new osgAnimation::BasicAnimationManager;
    bam->registerAnimation(animation.get());
    bam->playAnimation(animation.get());

    osg::ref_ptr<osg::Group> dummyDriverGroup = new osg::Group;
    dummyDriverGroup->addUpdateCallback(bam.get());
    dummyDriverGroup->addChild(root);

    viewer->setUpViewInWindow(200, 200, 800, 600);
    viewer->setSceneData(dummyDriverGroup);
    return viewer->run();
}

上面這個實現類似於osgAnimationsolid這個例子的實現方式,基本上是osgAnimation推薦的一種動畫的做法。

本文和上一篇文章(OSG動畫庫Animation解析(一))對osgAnimation的庫做了一個完整的剖析,關於動畫的權(weight)優先順序等內容,參考後續文章。