osg animate 操作_osganimate_lainegates的博客-程序员秘密

技术标签: osg  animation  

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();
}



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/LaineGates/article/details/15339291

智能推荐

Android 7.1 更改 OtherSound 默认值并隐藏_wubl2017的博客-程序员秘密

概述最近项目需要修改 Android 7.1 中 Settings 中 OtherSound 子菜单中各项的默认值,并将其隐藏,在此做下整理。更改默认值目标OtherSound子菜单中主要有三项,如下表所示。系统中默认这三项为开启的,根据项目要求需将其默认值改为关闭状态。Charging soundsLockscreen soundsTouch sounds做法(1)...

求一元组中的最长递增子序列的长度(Python)_IsQtion的博客-程序员秘密

如一个元祖 (2, 1, 6, 4, 5, 7, 4, 2, 5, 6, 1, 3, 2, 5), 他的最长递增子序列有很多, 比如(1,4,5,7或者1,2,3,5), 他的最长递增子序列长度就是4解法(一)思路介绍:可以借助一个辅助数组来完成, 这个辅助数组的主要职责是, 记录遍历到当前数时, 以当前数结尾的元祖的最长递增子序列长度, 通过嵌套两层while循环, 第一层遍历元祖, 第二层...

DBA重基础才能宽口径_weixin_34187822的博客-程序员秘密

话说遇到个刚毕业就找到工作的学生很嚣张,他居然觉得没必要在大学浪费时间学基础知识!什么是基础知识?基础就是练武的人练的马步。只有马步蹲好了,你才能下盘稳定,才能不被人一脚踢倒。如果,你要做一个C语言程序员,你就要会最起码的数据结构,但如果你胸无大志,就想干一个普通的,碌碌无为的码农,干一辈子,那也无所谓。DBA这个职业也同样如此,新炬数据库大师讲座上,新炬学院的讲师告诫广东工...

【WindowXP】net use 系统错误64_发生系统错误64_诗竹白芍的博客-程序员秘密

net use \\ip\ipc$ password /user:usernamepassword:对方主机密码username:对方主机用户名建立远程连接的时候发生了 错误64:指定网络名不可在用.首先检查防火墙是否关闭(不过一般防火墙没有关闭的话ping不同) 检查计算机服务中Computer Browser是否开启 若服务中无Computer Browser检查添加删除windows功能里面,是否有勾选"SMB....文件共享支持",勾上后重启电脑即可 之后再重复第二步,将C...

uefi能重置系统吗_uefi怎么修复引导?uefi修复引导详细教程(全自动)_倪修智的博客-程序员秘密

[文章导读]随着uefi+gpt(guid)分区的流行,越来越多的小伙伴经常遇到uefi引导丢失的情况,也不知道怎么修复,以前的一些修复工具都只能修复传统模式mbr格式下的硬引导,但对于uefi引导不是很清楚,uefi引导主要是靠分区中的esp分区来启动的,那么怎么进行修复uefi引导呢?接下来电脑系统城小编为大家分享详细的uefi引导修复教程。随着uefi+gpt(guid)分区的流行,越来越多...

python程序-->Collatz 序列问题_不写了光看看的咸鱼的博客-程序员秘密

这个问题是某本python书籍课后实践项目题,不过没给答案     内容大致如下:    编写一个名为collatz()的函数,有一个名为number的参数。如果参数是偶数,那么collatz()就打印number / /2 ,并返回其值。如果number是奇数,collatz()就打印并返回3 *number +1     改成程序,让用户输入任意一个数,通过对该数字不断调用coll

随便推点

编程之道(三部)_程序员四大奇书 编程之道_铁文的博客-程序员秘密

翻阅以前下载的文档,再读这两篇文章,有所感悟,贴。程序设计之道第一部寂静虚无篇    大师如是说:“学会从程序抓虫子之后,就可以毕业了。”1.1节    寂静虚无中有奥秘,不动不静,乃程序之源,吾无以名之,故称之为程序设计之道。    若道至善,则作业系统至善;若作业系统至善,编译程序亦然;若编译程序至善,则应用程序亦复如是,是故用户大善,世有和谐存焉。1.2节

使用BaseRecyclerViewAdapterHelper实现树形结构_baserecyclerviewadapterhelper树形_且白的博客-程序员秘密

使用BaseRecyclerViewAdapterHelper实现树形结构成品图先依赖数据bean写adapter在界面中使用成品图先依赖 implementation com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.30数据beanconst val ONE = 1;const val TWO = 2;const val THREE = 3;data class TreeOne( var label: String,

java加密算法简要介绍_亮了的blog的博客-程序员秘密

本篇内容简要介绍BASE64、MD5、SHA、HMAC几种加密算法。     BASE64编码算法不算是真正的加密算法。     MD5、SHA、HMAC这三种加密算法,可谓是非可逆加密,就是不可解密的加密方法,我们称之为单向加密算法。我们通常只把他们作为加密

最简单的基于FFmpeg的移动端例子:IOS 推流器_最简单的基于ffmpeg的推流器_雷霄骅的博客-程序员秘密

本文记录IOS平台下基于FFmpeg的推流器。该示例C语言的源代码来自于《最简单的基于FFMPEG的推流器》。相关的概念就不再重复记录了。源代码项目的目录结构如图所示。C代码位于ViewController.m文件中,内容如下所示。

update-script脚本语法说明_androiddeveloper的博客-程序员秘密

目前有好几种方法来安装软件或是库文件到你的Android手机上。你可以使用市场程序来查找并安装软件,也可以使用adb命令行工具来安装或是发送文件到你的Android文件系统中。这些方法对于操作单个文件来说都挺方便的,但是如果你需要一次性安装多个软件或是库文件时,那么最为方便的方法大概就是使用update.zip(也就是刷机包)文件了。Android系统使用恢复工具(recovery)来安装这个up

零散_weixin_30877493的博客-程序员秘密

零散 今天做的事太杂了,没啥好写的,就简单总结下这两天遇到的问题吧。关于OpenSSL的: OpenSSL的EVP是用来做加解密和Hash的好东西,OpenSSL实现了一堆算法,同时还提供了增加新算法的功能。前两天研究了一下,把新算法加到EVP里面还算方便,最大的好处是能简化代码,省事儿。但还是有两个问题:...

推荐文章

热门文章

相关标签