osgAnimation之动画管理器

转载 2016年05月31日 21:09:15
  • 简介

在上一节osgAnimation之作用对象一文中的UpdateMatrixTransform示例里面,我们自己通过添加UpdateCallback来实现动画,事实上osgAnimation已经为我们提供了基本的动画处理类BasicAnimationManager,这个类继承自NodeCallback,负责多个动画对象的管理,现在我们看看它究竟是如何实现的。

  • 动画管理器

动画管理器中涉及到如下的几个类:LinkVisitor、AnimationManagerBase、BasicAnimationManager下面我们一一来看这些类的实现。

  • LinkVisitor

LinkVisitor使用在AnimationManagerBase中的一个内部辅助类,用来遍历子场景下面的作用对象(UpdateMatrixTransform等),我们在开发代码中不会直接用到这个类,下面我们重点看看这个类的作用:代码如下

[cpp] view plain copy
  1. void LinkVisitor::apply(osg::Node& node)  
  2. {  
  3.     osg::StateSet* st = node.getStateSet();  
  4.     if (st)  
  5.         handle_stateset(st);  
  6.   
  7.     osg::NodeCallback* cb = node.getUpdateCallback();  
  8.     while (cb)  
  9.     {  
  10.         osgAnimation::AnimationUpdateCallbackBase* cba = dynamic_cast<osgAnimation::AnimationUpdateCallbackBase*>(cb);  
  11.         if (cba)  
  12.             link(cba);  
  13.         cb = cb->getNestedCallback();  
  14.     }  
  15.     traverse(node);  
  16. }  
  17.   
  18. void LinkVisitor::apply(osg::Geode& node)  
  19. {  
  20.     for (unsigned int i = 0; i < node.getNumDrawables(); i++)  
  21.     {  
  22.         osg::Drawable* drawable = node.getDrawable(i);  
  23.         if (drawable && drawable->getStateSet())  
  24.             handle_stateset(drawable->getStateSet());  
  25.     }  
  26.     apply(static_cast<osg::Node&>(node));  
  27. }  

LinkVisitor是一个NodeVisitor,看看它是实现我们知道它就是用来搜集作用对象的,并且将作用对象和Animation进行link(实质是将channel和作用对象进行了link)也就是将Channel中用来保存运算结果的Target对象设置为了作用对象中数组中元素的Target(即将StackedTransformElement中的target设置给了channel)

  • AnimationManagerBase

AnimationManagerBase是动画管理器的基类,它提供了动画管理器需要的基本功能,这个类是一个虚基类,需要派生类实现update成员函数。由于这个类是一个NodeCallback,它必然会重载operator()操作符,我们看一下它里面做了些什么:

[cpp] view plain copy
  1. void AnimationManagerBase::operator()(osg::Node* node, osg::NodeVisitor* nv)  
  2. {  
  3.     if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)  
  4.     {  
  5.         if (needToLink())  
  6.         {  
  7.             link(node);  
  8.         }  
  9.         const osg::FrameStamp* fs = nv->getFrameStamp();  
  10.         update(fs->getSimulationTime());  
  11.     }  
  12.     traverse(node,nv);  
  13. }  
对比一下我们在osgAnimation之作用对象中UpdateMatrixTransform的例子不难看出我们的PlayCallback与这个类很类似,这个update(fs->getSimulationTime())调用驱动了整个Animation动画,让整个动画一帧一帧的动起来。

此外我们在osgAnimation之作用对象中UpdateMatrixTransform的例子中将PlayCallback设置为动画子场景(球节点)的父节点,在场景遍历到动画子节点之前先通过PlayCallback来更新动画子节点之上MatrixTransform的矩阵值,从而达到遍历到动画子场景时变动子场景的位置实现动起来的效果。同理,这里AnimationManagerBase应该也是这样做到吧!没错,正是这样的。在上面代码中link(node)就是这么做的,我们看一看实现:

[cpp] view plain copy
  1. void AnimationManagerBase::link(osg::Node* subgraph)  
  2. {  
  3.     LinkVisitor* linker = getOrCreateLinkVisitor();  
  4.     linker->getAnimationList().clear();  
  5.     linker->getAnimationList() = _animations;  
  6.   
  7.     subgraph->accept(*linker);  
  8.     _needToLink = false;  
  9.     buildTargetReference();  
  10. }  
这里通过LinkVisitor将所有的StackedTransformElement的Target设置给了Channel,然后通过update(fs->getSimulationTime())来更新所有Channel中的Target的值。至于update(fs->getSimulationTime())究竟做了些什么,请接着往下阅读。

  • BasicAnimationManager

这个类正是集成了AnimationManagerBase类,同时重写了update方法,它也是我们在代码中最常使用的管理器类,现在看看在它的update中做了些什么:

[cpp] view plain copy
  1. void BasicAnimationManager::update (double time)  
  2. {  
  3.     _lastUpdate = time;   
  4.   
  5.     for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); ++it)  
  6.         (*it).get()->reset();  
  7.   
  8. // std::map键值从低到高,这里用了反向的迭代器,因此是按优先级从高到低进行操作的  
  9.     for( AnimationLayers::reverse_iterator iterAnim = _animationsPlaying.rbegin(); iterAnim != _animationsPlaying.rend(); ++iterAnim )  
  10.     {  
  11.         std::vector<int> toremove;  
  12.         int priority = iterAnim->first;  
  13.           
  14.         AnimationList& list = iterAnim->second;  
  15.         for (unsigned int i = 0; i < list.size(); i++)  
  16.         {  
  17.             if (! list[i]->update(time, priority))  
  18.             {  
  19.                 toremove.push_back(i);  
  20.             }   
  21.         }  
  22.         while (!toremove.empty())  
  23.         {  
  24.             list.erase(list.begin() + toremove.back());  
  25.             toremove.pop_back();  
  26.         }  
  27.     }  
  28. }  
这里的AnimationLayers是这样定义的:typedef std::map<int, AnimationList > AnimationLayers; 它是一个std::map,第一个元素代表了优先级,也就是在更新Target里面数据的时候是按照优先级从高到低进行的。在osgAnimation之作用对象中UpdateMatrixTransform的例子中我们仅仅是更新了一个Animation对象,这里更新了多个,但原理都是类似的。

  • 总结

结合上述的分析,我们知道了管理器做的工作实际上是使用一个更新回调驱动数据去完成更新。它需要这样几个过程:

1.将场景中的作用对象(UpdateMatrixTransform)中元素(也就是StackedTransformElement)的Target设置给Channel,这样建立起Target进行数据的传输纽带;这一过程通过LinkVisitor来完成。

2.更新回调中update的调用,这个update的调用起到一系列连锁反应,将Animation中所有Channel的update调用一遍,实质上是调用Channel里面所有Target的update,从而完成数据的更新,这一过程在BasicAnimationManager中update中完成。

本课内容的一个实例参看osg Examples 中osganimationsolid示例

转载地址:http://blog.csdn.net/csxiaoshui/article/details/22276775


相关文章推荐

osgAnimation之作用对象

简介 在前文osgAnimation之动画基础篇中介绍了osgAnimation中的几个基础的类元素,这其中Channel频道类集成了关键帧、插值算法、采样器、执行对象(Target),构成了动画...

OSG-场景动画基础知识_刚体动画

简单路径动画:    简单的路径动画不一定需要osgAnimation中丰富多彩的插值与关键帧采样机制,用户只需要输入某个对象节点在每个时刻的关键路径点、包括位置、旋转、缩放,就足以表达复杂的缸体动画...

OSG中的动画

OSG中的动画, AnimationPath, AnimationPathCallback, PositionAttitudeTransform的使用。 之前搞了两头牛了,但是它们都是静止的。现在我想...

osgAnimation之动画基础篇

简介 osgAnimation是osg库中提供场景动画效果的一个类库,它为我们提供了许多与场景动画相关的类,比如关键帧、插值、采样、频道、骨骼动画、材质变化等。本课就对osgAnimatio...

OSG中几何数据的更新显示

最简单的顶点数据更新方法是预先获取setVertexArray()所用的数组数据,并对其进行更新。但是对于开启显示列表支持的几何体(这是默认的情况)来说,有一个问题需要特别需要引起注意,即显示列表中的...

场景数据的动态更新

动态更新的核心就是设置数据变度属性DataVariance,它决定了OSG在多线程渲染的过程中的执行策略:只有所有DYNAMIC属性的对象被渲染完毕之后,OSG才会开始执行下一帧的用户更新操作;这样有...
  • L_Andy
  • L_Andy
  • 2015年11月27日 14:49
  • 1402

Android SpringAnimation 弹簧动画

前言 下午在掘金上看到了Android终于出了弹簧动画,马不停蹄的撸起代码,研究一下这个小家伙。毕竟ios的弹簧效果已经出来很久了。话不多说,先上效果图。效果图配置环境1. compile 'com...

OSG 路径动画学习

1、动画的实现方法: 通过设置回调函数使得节点实现按

OSG学习笔记3-使用回调实现旋转动画

这是有关节点的更新与事件回调,OSG中的节点主要是使用回调Callback来完成用户临时定义的,需要每帧执行的工作。 回调时一种用户编写的功能模块,它可以作为一个参数传递给其他功能模块,从而实现一些...

ocos2d-x 自建动画管理器AnimationManager的方法和使用

转载:http://farsa.blog.51cto.com/6172595/1132332/  代码出自魔塔 使用方法在代码后几行 //**********animat...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:osgAnimation之动画管理器
举报原因:
原因补充:

(最多只允许输入30个字)