目录

  • 本节功能
  • 具体实现
  • 实现要点
  • 本节所有代码

本节功能

在第36.4节 动画-路径动画中的角度控制问题中,我们在场景绘制了一个按固定路径飞行的飞机,在这一节中,我们将使用osg自带的osgGA::NodeTrackerManipulator 对飞机进行跟踪,在跟踪过程中可以使用鼠标拖动来任意的调整其观察角度,类似针对飞机的一个trackball操作器。

请使用浏览器打开,平时遇到问题或加群也可以加我微信:13324598743:
【击此打开网盘资源链接】

具体实现

按理说,我们只需要设置跟踪节点,并将当前的操作器设置为NodeTrackerManipulator就可以了,如下:

//跟踪操作器
osgGA::NodeTrackerManipulator* g_ntm = new osgGA::NodeTrackerManipulator;
viewer.setCameraManipulator(g_ntm);
g_ntm->setTrackNode(mt);

但是往往事情没有这么简单,这要从NodeTrackerManipulator的设计目标说起,导致了它不能适应有些场景。NodeTrackerManipulator的设计初衷是假如我们在一个地球上飞行,那么对飞机的跟踪就有很多的约束,比如说最好是能够绕飞机自带的Z轴旋转,而不是任意角度,这很符合常理。NodeTrackerManipulator出来的时候,还没有osgEarth,因此它判断是不是在地球上飞行则主要依赖其跟踪的物体的父结点有没有一个CoordinateSystemNode,所以本身跟踪一个运动物体是和地球没有关系的,但是其设计的目标却导致了其的有些操作的有效性依赖了CoordinateSystemNode。

我们可以在NodeTrackerManipulator的对于TrackerMode的注释中看到很多关于CoordinateSystemNode(csn)的描述。

好了,那么我们要实现跟踪物体,不管csn不csn的,那么就要注意了。

实现要点

1、 要在运动结点构造完毕后设置跟踪结点
比如我们要跟踪一个飞机,我们一般会这样:

//跟踪器
ntm = new NodeTrackerManipulator
//飞机模型
glider = osgDB::readNodeFile(glider.osg)
//调整飞机模型的姿态和大小
mt = new osg::MatrixTransform;
mt->addChild(glider);
//这个setMatrix是用来调整姿态和大小,并未运动
mt->setMatrix
//设置ntm跟踪这个结点
ntm->setTrackNode(mt)//运动结点
animateMt = new osg::MatrixTransform;
animateMt->addChild(mt);
//设置运动
animateMt->setUpdateCallback(animate)

结果不好使,为什么不好使呢,因为ntm->setTrackNode(mt)的时候会确定一个nodePath,以来确定这个结点是否在运动。这个时候的运动结点还没有加入。而这个nodePath不会更新,就设置这一回。

我们要修改的话,就需要在运动结点也加入完毕后,再来设置跟踪结点:

//添加运动的飞机
osg::Node* loadFly(osg::AnimationPath* animation)
{//用于旋转飞机,使其朝向合适osg::MatrixTransform* mt = new osg::MatrixTransform;osg::Node* glider = osgDB::readNodeFile("glider.osg");glider->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON);//飞机默认朝X轴负方向,我们绕Z轴转-90度,使其朝Y轴正方向mt->setMatrix(osg::Matrix::scale(5.0, 5.0, 5.0) * osg::Matrix::rotate(osg::inDegrees(-90.0), osg::Z_AXIS));mt->addChild(glider);//实际的路径控制osg::MatrixTransform* persionMT = new osg::MatrixTransform;persionMT->setUpdateCallback(new osg::AnimationPathCallback(animation));persionMT->addChild(mt);//跟踪操作器设置跟踪节点g_ntm->setTrackNode(mt);g_ntm->setTrackerMode(osgGA::NodeTrackerManipulator::NODE_CENTER_AND_ROTATION);g_ntm->setRotationMode(osgGA::NodeTrackerManipulator::TRACKBALL);g_ntm->setAutoComputeHomePosition(false);g_ntm->setDistance(40.0);return persionMT;
}

2、设置跟踪距离
在默认的情况下,视点的位置会在整个场景的包围盒外在的某一个位置,这不是我们想要的,我们只想要离我们跟踪的物体的包盒近一点,这个时候要进行如下设置,不再自动的计算场景的包围盒来计算视点:

g_ntm->setAutoComputeHomePosition(false);

到此设置就结束了,但是一个好的跟踪操作器其实还有很多的操作,比如跟踪不能拉的太近,初始的角度可以控制,也不能让视点可以拉的太远,旋转不能是任意的等等,这些都是NodeTrackerManipulator所不能的,尽管有setDistance, setRotate, setMinimumDistance, 但是这些都不起作用。这也给我们留下了新的课题。

本节所有代码

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osg/NodeVisitor>
#include <osg/Transform>
#include <osg/AnimationPath>
#include <osgGA/GUIEventHandler>
#include <osgUtil/LineSegmentIntersector>
#include <osg/ShapeDrawable>
#include <osg/LineWidth>
#include <osgAnimation/BasicAnimationManager>
#include <osg/MatrixTransform>
#include <osg/io_utils>
#include <osgGA/NodeTrackerManipulator>//跟踪操作器
osgGA::NodeTrackerManipulator* g_ntm = new osgGA::NodeTrackerManipulator;//给定顶点,和行进的速度,创建一个路径
osg::AnimationPath* CreateAnimate(osg::Vec3Array* keyPoint, float speed)
{//只有1个点,是形成不了路径的if (keyPoint->size() <= 1){return NULL;}osg::AnimationPath* animationPath = new osg::AnimationPath;animationPath->setLoopMode(osg::AnimationPath::LOOP);//关键点对应的时间float t = 0.0;//朝向osg::Quat rotate;for (int i = 0; i < keyPoint->size(); i++){//最后一个点,就把第一个点也压进去,形成环路if ((keyPoint->size() - 1) == i){//最后一个点的朝向不计算了,就用上一个点的朝向animationPath->insert(t, osg::AnimationPath::ControlPoint(keyPoint->at(i), rotate));//计算最后一个点的时间t += ((keyPoint->at(0) - keyPoint->at(i)).length() / speed);//第一个点的朝向还是指向第二个点rotate.makeRotate(osg::Y_AXIS, keyPoint->at(1) - keyPoint->at(0));animationPath->insert(t, osg::AnimationPath::ControlPoint(keyPoint->at(0), rotate));//循环结束break;}else{//其它点//如果是第一个点,时间上是t=0.0, 朝向上由第一个点和第二个点的朝向决定//计算当前点的朝向,因为我们的朝向只在一个轴上水平的变化,所以可以用简单的方法//视口默认朝Y轴,我们要将其转到由第一个点看向第二个点的向量rotate.makeRotate(osg::Y_AXIS, keyPoint->at(i + 1) - keyPoint->at(i));animationPath->insert(t, osg::AnimationPath::ControlPoint(keyPoint->at(i), rotate));}//两点间的距离除以速度t += ((keyPoint->at(i + 1) - keyPoint->at(i)).length() / speed);}return animationPath;
}//创建一个红球做标志,给定圆心和半径
osg::Node* CreateSphere(osg::Vec3 center, float r)
{osg::Geode* gnode = new osg::Geode;osg::ShapeDrawable* sd = new osg::ShapeDrawable(new osg::Sphere(center, r));sd->setColor(osg::Vec4(1.0, 0.0, 0.0, 1.0));//红色gnode->addDrawable(sd);return gnode;
}//创建线,给定顶点和红宽,
osg::Node* CreateLine(osg::Vec3Array* vertex, float lineWidth)
{osg::Geode* gnode = new osg::Geode;osg::Geometry* geom = new osg::Geometry;gnode->addDrawable(geom);//设置顶点geom->setVertexArray(vertex);//设置颜色osg::Vec4Array* color = new osg::Vec4Array();color->push_back(osg::Vec4(1.0, 0.0, 0.0, 1.0));geom->setColorArray(color, osg::Array::BIND_OVERALL);//设置线宽osg::LineWidth* lw = new osg::LineWidth(lineWidth);geom->getOrCreateStateSet()->setAttribute(lw, osg::StateAttribute::ON | osg::StateAttribute::PROTECTED);//关闭灯光显得亮一点geom->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);//设置添加为线geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP, 0, vertex->size()));return gnode;
}osg::Group* createMark(osg::Vec3Array* keyPoint)
{osg::Group* markGroup = new osg::Group();//添加红球做关键点for (int i = 0; i < keyPoint->size(); i++){markGroup->addChild(CreateSphere(keyPoint->at(i), 1.0));}//添加线markGroup->addChild(CreateLine(keyPoint, 1.0));return markGroup;
}//添加运动的飞机
osg::Node* loadFly(osg::AnimationPath* animation)
{//用于旋转飞机,使其朝向合适osg::MatrixTransform* mt = new osg::MatrixTransform;osg::Node* glider = osgDB::readNodeFile("glider.osg");glider->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON);//飞机默认朝X轴负方向,我们绕Z轴转-90度,使其朝Y轴正方向mt->setMatrix(osg::Matrix::scale(5.0, 5.0, 5.0) * osg::Matrix::rotate(osg::inDegrees(-90.0), osg::Z_AXIS));mt->addChild(glider);//实际的路径控制osg::MatrixTransform* persionMT = new osg::MatrixTransform;persionMT->setUpdateCallback(new osg::AnimationPathCallback(animation));persionMT->addChild(mt);//跟踪操作器设置跟踪节点g_ntm->setTrackNode(mt);g_ntm->setTrackerMode(osgGA::NodeTrackerManipulator::NODE_CENTER_AND_ROTATION);g_ntm->setRotationMode(osgGA::NodeTrackerManipulator::TRACKBALL);g_ntm->setAutoComputeHomePosition(false);g_ntm->setDistance(40.0);return persionMT;
}int main()
{osgViewer::Viewer viewer;//里面存放的是路径上的关键点osg::Vec3Array* keyPoint = new osg::Vec3Array;keyPoint->push_back(osg::Vec3(-5.15, -88.89, 8.0));keyPoint->push_back(osg::Vec3(50.1688, -62.9621, 39.0));keyPoint->push_back(osg::Vec3(79.1318, -46.6088, 15.0));keyPoint->push_back(osg::Vec3(80.03, -26.95, 29.0));keyPoint->push_back(osg::Vec3(81.41, -6.42, 12.0));keyPoint->push_back(osg::Vec3(70.11, 12.47, 29.0));keyPoint->push_back(osg::Vec3(57.51, 28.49, 12.0));keyPoint->push_back(osg::Vec3(38.83, 45.23, 29.0));keyPoint->push_back(osg::Vec3(6.98, 61.87, 12.0));keyPoint->push_back(osg::Vec3(-23.46, 43.42, 29.0));keyPoint->push_back(osg::Vec3(-36.27, 22.40, 15.0));keyPoint->push_back(osg::Vec3(-42.94, -13.22, 29.0));keyPoint->push_back(osg::Vec3(-60.78, -41.55, 8.0));keyPoint->push_back(osg::Vec3(-41.95, -49.65, 29.0));osg::Node* ceep = osgDB::readNodeFile("ceep.ive");//场景ceeposg::Group* root = new osg::Group;root->addChild(ceep);//关键点和路径的标记root->addChild(createMark(keyPoint));//添加运动的飞机osg::Node* fly = loadFly(CreateAnimate(keyPoint, 3.0));root->addChild(fly);viewer.setCameraManipulator(g_ntm);viewer.setSceneData(root);return viewer.run();
}

第36.5节 动画-跟踪运动中物体的操作器相关推荐

  1. MIT:大脑如何跟踪运动中的物体?

    来源:脑健康联盟 抓住一个弹起的球,或者用球拍击球,这两种行动都需要合理地估算触球时间.一直以来,神经科学家都相信,大脑是通过计算物体的运动速度来完成这些动作的. 然而,麻省理工学院的一项新研究表明, ...

  2. 第36.1节 动画-刚体动画控制

    目录 本节功能 具体实现 存放动画 寻找动画 播放/暂停 复位 加速/减速 最后用一个事件响应来联接这一切 所有代码 本节功能 本节后几个章节会介绍和动画有关的课程. 本节实现一个从3DMAX导出的地 ...

  3. java:计算自由落体运动中物体的位移

    eclipse使用Java编写自由落体 文章目录 前言 方案 代码实现 前言 自由落体公式:s = 1/2 × g × t2 其中: s (位移(m) t (时间(s) g (重力加速度(9.8m/s ...

  4. 多目视频跟踪问题中的物体表示方法探究

    本文节选自清华大学陈龙博士的毕业论文:单目和多目视频中的线上多物体跟踪方法研究. 引言 如何表示物体是跟踪算法需要考虑的首要问题.跟踪问题中物体的定义是宽泛的,它可以是任何在后续分析和处理的过程中我们 ...

  5. 第8节 实例-写个简单的操作器

    缘由 应四川的群友:挑战高起点 的要求,我给大家写一个最简单的操作器,读完本文以最大程度让读者掌握在OSG中写个操作器是咋回事儿.代码在最后一个代码块,直接新建OSG工程,拷贝进去就可以运行.特别感谢 ...

  6. Android动画效果-更新中

    概述 Android系统提供了三种实现动画的方式,一种是补间动画(Tween Animation 在SDK中成为View Animation),另一种是帧动画(Frame Animation 在SDK ...

  7. 基于matlab介绍传感器融合和跟踪工具箱中用于评估跟踪器性能的不同定量分析工具(附源码)

    目录 一.分配和错误指标 1.1 轨道和真相定义 1.2 计算和分析指标 1.3 分析分配指标 ​编辑 1.4 分析错误指标 ​编辑二.将指标汇总为分数 2.1 欧斯帕公制 2.2 分析 OSPA 指 ...

  8. 《Nmap渗透测试指南》—第2章2.15节路由跟踪

    本节书摘来自异步社区<Nmap渗透测试指南>一书中的第2章2.15节路由跟踪,作者 商广明,更多章节内容可以访问云栖社区"异步社区"公众号查看. 2.15 路由跟踪 表 ...

  9. 一周AI新闻 | 追踪眼球找BUG,AI可从眼球运动中学习

     追踪眼球找 BUG   AI 智能体可从眼球运动中学习  「 程序员的眼里有什么? 」 人类在从事认知要求高的任务时所做的眼球运动其实暗藏很多沟通.而一个有经验的程序员会将注意力放在程序的信息部分以 ...

最新文章

  1. linux系统终端介绍
  2. join left semi_HIVE--left semi join
  3. 前端学习(1961)vue之电商管理系统电商系统之调用api获取数据
  4. mysql数据库校对_mysql数据库校对原则
  5. C# 基础系列--程序集三
  6. SylixOS arm64 自旋锁
  7. 手把手教大家如何优化长尾关键词
  8. 微博开放平台api使用
  9. steam游戏直连工具
  10. XMind 8 pro 破解教程
  11. 热烈祝贺高分十三号卫星发射成功
  12. excel 计算复合增长率
  13. 奈奎斯特采样定理—以二维图像为例
  14. Excel 单元格中插入附件
  15. python多线程爬取ts文件并合成mp4视频
  16. linux7关闭isdn,在Linux下使用ISDN拨号上网
  17. Failed to load JavaHL Library问题
  18. matlab稳态数值解,matlab解稳态导热问题
  19. SWF文件加密器 V9.0
  20. amlogic ap6210 wifi bt驱动移植

热门文章

  1. 重装VS6时,弹出Setup Was Unable to Create a DCOM User Account错误的解决方法
  2. UAP开发步骤详解(很详细哦)---②单据向导开发
  3. linux下的c语言实现象棋,用C语言实现中国象棋
  4. 单元测试断言库:chai.js中文文档
  5. 产品经理——java学习之路
  6. thymleaf 使用三目运算多个条件判断的写法
  7. element ui中的el-input回车键事件
  8. 保护私密文件夹,可以这样设置隐藏起来
  9. C语言中的if、else if 的用法和区别
  10. 2. 硬件基础知识学习