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();
}
概述最近项目需要修改 Android 7.1 中 Settings 中 OtherSound 子菜单中各项的默认值,并将其隐藏,在此做下整理。更改默认值目标OtherSound子菜单中主要有三项,如下表所示。系统中默认这三项为开启的,根据项目要求需将其默认值改为关闭状态。Charging soundsLockscreen soundsTouch sounds做法(1)...
如一个元祖 (2, 1, 6, 4, 5, 7, 4, 2, 5, 6, 1, 3, 2, 5), 他的最长递增子序列有很多, 比如(1,4,5,7或者1,2,3,5), 他的最长递增子序列长度就是4解法(一)思路介绍:可以借助一个辅助数组来完成, 这个辅助数组的主要职责是, 记录遍历到当前数时, 以当前数结尾的元祖的最长递增子序列长度, 通过嵌套两层while循环, 第一层遍历元祖, 第二层...
话说遇到个刚毕业就找到工作的学生很嚣张,他居然觉得没必要在大学浪费时间学基础知识!什么是基础知识?基础就是练武的人练的马步。只有马步蹲好了,你才能下盘稳定,才能不被人一脚踢倒。如果,你要做一个C语言程序员,你就要会最起码的数据结构,但如果你胸无大志,就想干一个普通的,碌碌无为的码农,干一辈子,那也无所谓。DBA这个职业也同样如此,新炬数据库大师讲座上,新炬学院的讲师告诫广东工...
net use \\ip\ipc$ password /user:usernamepassword:对方主机密码username:对方主机用户名建立远程连接的时候发生了 错误64:指定网络名不可在用.首先检查防火墙是否关闭(不过一般防火墙没有关闭的话ping不同) 检查计算机服务中Computer Browser是否开启 若服务中无Computer Browser检查添加删除windows功能里面,是否有勾选"SMB....文件共享支持",勾上后重启电脑即可 之后再重复第二步,将C...
[文章导读]随着uefi+gpt(guid)分区的流行,越来越多的小伙伴经常遇到uefi引导丢失的情况,也不知道怎么修复,以前的一些修复工具都只能修复传统模式mbr格式下的硬引导,但对于uefi引导不是很清楚,uefi引导主要是靠分区中的esp分区来启动的,那么怎么进行修复uefi引导呢?接下来电脑系统城小编为大家分享详细的uefi引导修复教程。随着uefi+gpt(guid)分区的流行,越来越多...
这个问题是某本python书籍课后实践项目题,不过没给答案 内容大致如下: 编写一个名为collatz()的函数,有一个名为number的参数。如果参数是偶数,那么collatz()就打印number / /2 ,并返回其值。如果number是奇数,collatz()就打印并返回3 *number +1 改成程序,让用户输入任意一个数,通过对该数字不断调用coll
翻阅以前下载的文档,再读这两篇文章,有所感悟,贴。程序设计之道第一部寂静虚无篇 大师如是说:“学会从程序抓虫子之后,就可以毕业了。”1.1节 寂静虚无中有奥秘,不动不静,乃程序之源,吾无以名之,故称之为程序设计之道。 若道至善,则作业系统至善;若作业系统至善,编译程序亦然;若编译程序至善,则应用程序亦复如是,是故用户大善,世有和谐存焉。1.2节
使用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,
本篇内容简要介绍BASE64、MD5、SHA、HMAC几种加密算法。 BASE64编码算法不算是真正的加密算法。 MD5、SHA、HMAC这三种加密算法,可谓是非可逆加密,就是不可解密的加密方法,我们称之为单向加密算法。我们通常只把他们作为加密
本文记录IOS平台下基于FFmpeg的推流器。该示例C语言的源代码来自于《最简单的基于FFMPEG的推流器》。相关的概念就不再重复记录了。源代码项目的目录结构如图所示。C代码位于ViewController.m文件中,内容如下所示。
目前有好几种方法来安装软件或是库文件到你的Android手机上。你可以使用市场程序来查找并安装软件,也可以使用adb命令行工具来安装或是发送文件到你的Android文件系统中。这些方法对于操作单个文件来说都挺方便的,但是如果你需要一次性安装多个软件或是库文件时,那么最为方便的方法大概就是使用update.zip(也就是刷机包)文件了。Android系统使用恢复工具(recovery)来安装这个up
零散 今天做的事太杂了,没啥好写的,就简单总结下这两天遇到的问题吧。关于OpenSSL的: OpenSSL的EVP是用来做加解密和Hash的好东西,OpenSSL实现了一堆算法,同时还提供了增加新算法的功能。前两天研究了一下,把新算法加到EVP里面还算方便,最大的好处是能简化代码,省事儿。但还是有两个问题:...