osg示例解析之osganimationtimeline(1)
来源:互联网 发布:天虹商场怎么样知乎 编辑:程序博客网 时间:2024/05/18 12:29
简介
本示例主要使用了osgAnimation中的timeline时间线的方式来管理场景中的动画。时间线的概念有点像把三维的渲染过程分成一帧一帧,打个比喻:timeline有点像在看动画片的时候用相机把正在播放的动画片场景按固定间隔拍摄成一张张的照片,最后把这一张张的照片管理起来,有点像反向模拟动画的过程。
示例
这个示例只能用Nathan.osg这个模型来运行,因为代码中的Animation动画依赖这个文件的内容,我们可以打开Nathan.osg看看,可以发现这样几段内容:
osgAnimation::Animation { UniqueID uniqid_Animation_698 name "Idle_Main" num_channels 66 Vec3LinearChannel { name "scale" target "Foot_IK.L" Keyframes 51 { key 0.00000 1.00000 1.00000 1.00000 key 0.04000 1.00000 1.00000 1.00000 key 0.08000 1.00000 1.00000 1.00000 key 0.12000 1.00000 1.00000 1.00000 key 0.16000 1.00000 1.00000 1.00000 key 0.20000 1.00000 1.00000 1.00000 key 0.24000 1.00000 1.00000 1.00000 ......可以看到这个Idle_Main正好是Nathan.osg中的一段关键帧动画,同样源码中的Idle_Head_Scratch.02以及Idle_Nose_Scratch.01也可以在Nathan.osg中找到它们对应的动画
- Callback定义
struct NoseBegin : public osgAnimation::Action::Callback{ virtual void operator()(osgAnimation::Action* action, osgAnimation::ActionVisitor* nv) { std::cout << "sacrebleu, it scratches my nose, let me scratch it" << std::endl; std::cout << "process NoseBegin call back " << action->getName() << std::endl << std::endl; }};struct NoseEnd : public osgAnimation::Action::Callback{ virtual void operator()(osgAnimation::Action* action, osgAnimation::ActionVisitor* nv) { std::cout << "shhhrt shrrrrt shhhhhhrrrrt, haaa it's better"<< std::endl; std::cout << "process NoseEnd call back " << action->getName() << std::endl << std::endl; }};
这两段Callback定义在Nose_Scratch Action下面,它们会在某一个时刻被调用。Callback定义在Action之中,它们为的是实现在某一个Action中某一时刻被调用。而这些Action会在场景动画的某一个时间线上被调用(有点像我们之前打的比喻,在某一张拍摄照片绑定了一个Action,在这一时间到来时这个Action会被触发来运行它所包含的动画和回调)
_scratchNose->setCallback(0.0, new NoseBegin); _scratchNose->setCallback(_scratchNose->getNumFrames()-1, new NoseEnd);可以知道它们在_scratchNose开始时(0.0)以及_scratchNose结束时被调用。
- 定义Action
在代码中Action定义在NodeCallback(ExampleTimelineUsage)之中
_releaseKey = false; _manager = manager; const osgAnimation::AnimationList& list = _manager->getAnimationList(); osgAnimation::AnimationMap map; for (osgAnimation::AnimationList::const_iterator it = list.begin(); it != list.end(); it++) map[(*it)->getName()] = *it; _mainLoop = new osgAnimation::ActionStripAnimation(map["Idle_Main"].get(),0.0,0.0); _mainLoop->setLoop(0); // means forevermap["Idle_Head_Scratch.02"]->setDuration(4.0); _scratchHead = new osgAnimation::ActionStripAnimation(map["Idle_Head_Scratch.02"].get(),0.2,0.3); _scratchHead->setLoop(1); // one time map["Idle_Nose_Scratch.01"]->setDuration(10.0); // set this animation duration to 10 seconds _scratchNose = new osgAnimation::ActionStripAnimation(map["Idle_Nose_Scratch.01"].get(),0.2,0.3); _scratchNose->setLoop(1); // one time // add the main loop at priority 0 at time 0. osgAnimation::Timeline* tml = _manager->getTimeline(); tml->play(); tml->addActionAt(0.0, _mainLoop.get(), 0); // add a scratch head priority 1 at 3.0 second. tml->addActionAt(5.0, _scratchHead.get(), 1); // populate time with scratch head for (int i = 1; i < 20; i++) { // we add a scratch head priority 1 each 10 second // note: // it's possible to add the same instance more then once on the timeline // the only things you need to take care is if you remove it. It will remove // all instance that exist on the timeline. If you need to differtiate // it's better to create a new instance tml->addActionAt(5.0 + 10.0 * i, _scratchHead.get(), 1); } // we will add the scratch nose action only when the player hit a key // in the operator() // now we will add callback at end and begin of animation of Idle_Nose_Scratch.02 _scratchNose->setCallback(0.0, new NoseBegin); _scratchNose->setCallback(_scratchNose->getNumFrames()-1, new NoseEnd);
将它们添加到Timeline之中,设置在弹起键盘上按键的时候添加一个Action
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) { if (_releaseKey) // we hit a key and release it execute an action { osgAnimation::Timeline* tml = _manager->getTimeline(); // dont play if already playing if (!tml->isActive(_scratchNose.get())) { // add this animation on top of two other // we add one to evaluate the animation at the next frame, else we // will miss the current frame tml->addActionAt(tml->getCurrentFrame() + 1, _scratchNose.get(), 1); } _releaseKey = false; } }
- 添加管理器
和其他管理器一样的使用方式,在场景中添加管理器到节点中
osg::ref_ptr<osgAnimation::TimelineAnimationManager> tl = new osgAnimation::TimelineAnimationManager(*animationManager); root->setUpdateCallback(tl.get()); ExampleTimelineUsage* callback = new ExampleTimelineUsage(tl.get()); root->setEventCallback(callback); root->getUpdateCallback()->addNestedCallback(callback);
附:这个示例中存在一个Bug,Idle_Head_Scratch.02并不会被调用,需要我们添加该动作的时间,使用setDuration设置一个Action运行的时候就好了。
0 0
- osg示例解析之osganimationtimeline(1)
- osg示例解析之osganimationsolid(1)
- osg示例解析之osganimationmorph(1)
- osg示例解析之osganimationskinning(1)
- osg示例解析之osgparticle(1)
- osg示例解析之osgtexture1D(1)
- osg示例解析之osgatomiccounter(1)
- osg示例解析之osgcamera(1)
- osg示例解析之osgLight(1)
- osg示例解析之osgLight(1)
- osg示例解析之osganimationmorph(1)
- osg示例解析之osganimationskinning
- osg示例解析之osgcamera
- osg示例程序解析之osgterrain
- osg 示例程序解析之osgdelaunay
- osg示例程序解析1----osganimate
- osg示例代码解析---osgdelaunay
- osg示例程序解析2---osganimationeasemotion
- linux定时执行工具crontab 详解
- 孔学与企业管理
- Sql连接查询的几种方式
- 如何修改MFC的图标
- B/S
- osg示例解析之osganimationtimeline(1)
- addbatch executebatch
- 算法系列15天速成——第四天 五大经典查找【上】
- c# 温故而知新: 线程篇
- Android API Guides 之 App Components(16) - App Widgets
- 【编程好习惯】判断函数的返回值
- 浅谈HTTP中Get与Post的区别
- Java多态性详解——父类引用子类对象
- AD 控制域 相关命令