OSG 飞机路径动画控制

OSG 飞机路径动画控制

注:摘自《三维渲染引擎编程指南》


本文实现一个飞机,在地图上空盘旋,读者可以根据自己需要进行更改;
代码如下:
//2017. 8 .29
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>

#include <osg/Node>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Math>
#include <osg/AnimationPath>
#include <osg/MatrixTransform>
#include <osg/PositionAttitudeTransform>

#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

#include <osgUtil/Optimizer>


//路径动画控制事件
class AnimationEventHandler : public osgGA::GUIEventHandler
{
public:
	AnimationEventHandler(osgViewer::Viewer &vr):viewer(vr){}

	//事件处理
	virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &)
	{
		//创建动画更新回调对象
		osg::ref_ptr<osg::AnimationPathCallback> animationPathCallback = new osg::AnimationPathCallback();

		osg::ref_ptr<osg::Group> group = dynamic_cast<osg::Group*>(viewer.getSceneData());

		//取得节点的动画属性
		animationPathCallback = dynamic_cast<osg::AnimationPathCallback*>(group->getChild(0)->getUpdateCallback());

		switch(ea.getEventType())
		{
		case (osgGA::GUIEventAdapter::KEYDOWN):
			{
				if (ea.getKey() == 'p')
				{
					//暂停
					animationPathCallback->setPause(true);
					return true;
				}
				if (ea.getKey() == 'k')
				{
					//开始
					animationPathCallback->setPause(false);
					return true;
				}
				if (ea.getKey() == 'r')
				{
					//重新开始
					animationPathCallback->reset();
					return true;
				}

				break;
			}

		default:
			break;
		}
		return false;
	}

public:
	osgViewer::Viewer &viewer;
};

//创建路径
osg::ref_ptr<osg::AnimationPath> creatAnimationPath(osg::Vec3 ¢er, float radius, float looptime)
{
	//创建一个Path对象
	osg::ref_ptr<osg::AnimationPath> animationPath = new osg::AnimationPath();
    //设置动画模式为循环(LOOP)
	//LOOP:循环  SWING:单摆   NO_LOOPING:不循环
	animationPath->setLoopMode(osg::AnimationPath::LOOP);

	//关键点数
	int numPoint = 60;

	//每次偏移角度
	float yaw = 0.0f;
	float yaw_delta = 2.0 * osg::PI / ((float)(numPoint - 1.0f));

	//倾斜角度
	float roll = osg::inDegrees(45.0f);

	//时间偏移
	float time = 0.0f;
	float time_delta = looptime / ((float)(numPoint));

	for (int i = 0; i < numPoint; i++)
	{
		//关键点位置
		osg::Vec3 position(center + osg::Vec3(sinf(yaw) * radius, cosf(yaw) * radius,0.0f));

		//关键点角度
		osg::Quat rotation(osg::Quat(roll, osg::Vec3(0.0, 1.0, 0.0)) * osg::Quat( -(yaw + osg::inDegrees(90.f)), osg::Vec3(0.0, 0.0, 1.0)));

		//插入Path,把关键点与时间压入形成Path
		animationPath->insert(time, osg::AnimationPath::ControlPoint(position, rotation));

		yaw += yaw_delta;
		time += time_delta;
	}

	//返回Path
	return animationPath.get();
}


int main()
{
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
	osg::ref_ptr<osg::Group> root = new osg::Group();

	//读入飞机模型
	osg::ref_ptr<osg::Node> cessna = osgDB::readNodeFile("cessna.osg");

	//读入地形模型
	osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("lz.osg");

	//得到包围盒,来确定动画旋转中心
	const osg::BoundingSphere &bs = cessna->getBound();
	osg::Vec3 position = bs.center() + osg::Vec3(0.0f, 0.0f, 200.f);
	//缩放比例,如果比例不当,模型会看不见
	float size = 100.0f / bs.radius() * 0.3f;

	//创建路径
	osg::ref_ptr<osg::AnimationPath> animationPath = new osg::AnimationPath();
	animationPath = creatAnimationPath(position, 200.0f, 10.0f);
	osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform();

	//OSG确保只有STATIC数据可以进行图形渲染
	mt->setMatrix(osg::Matrix::translate( -bs.center()) * osg::Matrix::scale(size, size, size) * osg::Matrix::rotate(osg::inDegrees(-180.0f), 0.0f,0.0f,1.0f));
    mt->addChild(cessna.get());

	osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform();
	//设置更新回调
	pat->setUpdateCallback(new osg::AnimationPathCallback(animationPath.get(), 0.0f, 1.0f));
	pat->addChild(mt.get());

	root->addChild(pat.get());
	root->addChild(node.get());

	//优化场景数据
	osgUtil::Optimizer optimizer;
	optimizer.optimize(root.get());

	viewer->setSceneData(root.get());

	//添加路径动画
	viewer->addEventHandler(new AnimationEventHandler(*(viewer.get())));

	viewer->realize();
	viewer->run();

	return 0;

}

  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要实现osg目标选中动画,可以使用以下步骤: 1. 创建一个osg::AnimationPath对象,该对象表示动画路径。可以使用osg::AnimationPath::ControlPoint类来定义路径上的关键帧。 2. 将目标对象添加到场景图中,并使用osg::PositionAttitudeTransform类将其放置在场景中的适当位置。 3. 创建osg::AnimationPathCallback对象,并将其附加到目标对象的osg::Drawable上。设置AnimationPathCallback对象的动画路径为步骤1中创建的路径。 4. 在选中目标时,将目标对象的osg::AnimationPathCallback对象启用,使其开始播放动画。 5. 在取消选中目标时,禁用目标对象的osg::AnimationPathCallback对象,使其停止播放动画。 以下是一个示例代码: ```cpp osg::ref_ptr<osg::AnimationPath> animationPath = new osg::AnimationPath; osg::ref_ptr<osg::AnimationPath::ControlPoint> start = new osg::AnimationPath::ControlPoint; osg::ref_ptr<osg::AnimationPath::ControlPoint> end = new osg::AnimationPath::ControlPoint; start->setPosition(osg::Vec3(0,0,0)); start->setRotation(osg::Quat(0, osg::Vec3(0,0,1))); start->setTime(0.0); end->setPosition(osg::Vec3(0,0,1)); end->setRotation(osg::Quat(3.14159f, osg::Vec3(0,0,1))); end->setTime(1.0); animationPath->insert(0.0f, *start); animationPath->insert(1.0f, *end); osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform; pat->setPosition(osg::Vec3(0,0,0)); pat->addChild(target); osg::ref_ptr<osg::AnimationPathCallback> animationCallback = new osg::AnimationPathCallback(animationPath); target->getOrCreateStateSet()->setMode(GL_NORMALIZE, osg::StateAttribute::ON); target->setUpdateCallback(animationCallback); // 选中目标时 animationCallback->setPause(false); // 取消选中目标时 animationCallback->setPause(true); ``` 在这个例子中,我们创建了一个包含两个关键帧的动画路径,然后将其附加到目标对象的osg::AnimationPathCallback对象上。在选中目标时,我们启用该对象,使其开始播放动画,在取消选中目标时,禁用该对象,使其停止播放动画

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值