一.  操作器

OSG经常用到的自带操作器为TrackBall, osgEarth经常用到的自带操作器为EarthManipulator

自己要写操作器应继承于osgGA::CameraManipulator

流程:1. 设置自定义操作器  2. viewer在帧绘制时候取操作器控制的矩阵,(矩阵控制一般重载getMatrix()和getInverseMatrix()函数),然后更新camera    3. 有事件发生则调用handle更新矩阵

二. 碰撞检测

原理:老点与新点之间的连线是否与模型或任何node相交。

osg中有一个完成该碰撞检测的类:osgUtil::IntersectVisitor

三. 上楼梯

原理:1. 原始位置在1,假设需要上楼梯到3

2. 首先计算出2的点坐标,做一条垂直的虚线A,计算该直线与场景的交点;a.没有交点,说明不存在楼梯,无法移动 b.交点与点2距离较大,无法移动;c.存在一个位置点3可以移动

3. 若c,则做一条平行于1.2连线的线段B,注意是线段。B可以往上移一点,确保点1,3之间就算有障碍依然可以移动。若B线与场景没有交点,则上楼梯成功。

osg里面可以用LineSegmentIntersector取出线段与物体的交点。

csouth.h

//操作器功能:按键盘上W、S、A、D时,视口会前后左右移动
//加入了碰撞检测#pragma once#include "osgGA/CameraManipulator"
#include "osgViewer/Viewer"
#include "osgUtil/IntersectVisitor"
#include "osg/LineSegment"class CSouth : public osgGA::CameraManipulator
{public:CSouth();~CSouth();virtual void setByMatrix(const osg::Matrixd &matrix){};//直接通过矩阵设置视口,这里不提供这个方法virtual osg::Matrixd getMatrix() const;virtual void setByInverseMatrix(const osg::Matrixd &matrix){};virtual osg::Matrixd getInverseMatrix() const;virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us);bool changePosition(osg::Vec3 delta);void setStep(int delta_step);//改变移动步长,使其可以加速移动void setMnode(osg::Node* node);private:osg::Vec3 m_vPosition;  //视点当前位置osg::Vec3 m_vRotation;  //视点当前朝向int m_vStep;  //行进的步长float m_vRotateStep;  //代表鼠标拖动将要旋转的尺度//因为要在鼠标单击时进行拖动时旋转视口,因此必须纪录滑动的起点,在终点计算时要减去起点int m_iLeftX;int m_iLeftY;bool m_bLeftDown;//纪录左键是否按下osg::Node* m_node;//用作碰撞检测并将其设置为碰撞检测的节点
};

csouth.cpp

#include "csouth.h"CSouth::CSouth()
{m_vPosition = osg::Vec3(0, 0, 5);m_vRotation = osg::Vec3(osg::PI, 0, 0);//达到站立在地面的效果,平视XY面可以设置成(0,0,0)m_vStep = 1.0;m_vRotateStep = 0.01;//旋转力度设置成0.01是一个经验值,代表旋转力度m_bLeftDown = false;m_node = 0;
}CSouth::~CSouth()
{}
osg::Matrixd CSouth::getMatrix() const
{osg::Matrixd mat;mat.makeTranslate(m_vPosition);return osg::Matrixd::rotate(m_vPosition[0], osg::X_AXIS, m_vRotation[1], osg::Y_AXIS, m_vRotation[2], osg::Z_AXIS)*mat;
}
osg::Matrixd CSouth::getInverseMatrix() const
{osg::Matrixd mat;mat.makeTranslate(m_vPosition);return osg::Matrixd::inverse( osg::Matrixd::rotate(m_vPosition[0], osg::X_AXIS, m_vRotation[1], osg::Y_AXIS, m_vRotation[2], osg::Z_AXIS)*mat);
}
bool CSouth::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us)
{osgViewer::Viewer* view = dynamic_cast<osgViewer::Viewer*>(&us);switch (ea.getEventType()){case osgGA::GUIEventAdapter::KEYDOWN:{if (ea.getKey() == 'w' || ea.getKey() == 'W'){//原//changePosition(osg::Vec3(0, m_vStep, 0));/*改成这一句是为了实现无论视口朝向哪里,按w视点向前走,按s视点向后退,按a视点向左,按d视点像右因为此时移动视点和视口当前的朝向有关。因为变量m_vRotation中纪录了与各轴的夹角,因此只需要将此夹角求出;将要走的步长delta变为x轴与y轴两个方向的分量*/changePosition(osg::Vec3d(m_vStep*cosf(osg::PI_2 + m_vRotation._v[2]), m_vStep*sinf(osg::PI_2 + m_vRotation._v[2]), 0));}else if (ea.getKey() == 's' || ea.getKey() == 'S'){//changePosition(osg::Vec3(0, -m_vStep, 0));changePosition(osg::Vec3d(-m_vStep*cosf(osg::PI_2 + m_vRotation._v[2]), -m_vStep*sinf(osg::PI_2 + m_vRotation._v[2]), 0));}else if (ea.getKey() == 'a' || ea.getKey() == 'A'){//changePosition(osg::Vec3(-m_vStep, 0,0));changePosition(osg::Vec3d(-m_vStep*sinf(osg::PI_2 + m_vRotation._v[2]), m_vStep*cosf(osg::PI_2 + m_vRotation._v[2]), 0));}else if (ea.getKey() == 'd' || ea.getKey() == 'D'){//changePosition(osg::Vec3(m_vStep, 0, 0));changePosition(osg::Vec3d(m_vStep*sinf(osg::PI_2 + m_vRotation._v[2]), -m_vStep*cosf(osg::PI_2 + m_vRotation._v[2]), 0));}else if (ea.getKey() == '+'){setStep(1);}else if (ea.getKey() == '-'){setStep(-1);}else if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Home){changePosition(osg::Vec3(0, 0, 1.0));//视口向上升}else if (ea.getKey() == osgGA::GUIEventAdapter::KEY_End){changePosition(osg::Vec3(0, 0, -1.0));//视口向下降}}break;case osgGA::GUIEventAdapter::PUSH:{//单击了左键则纪录单击的位置放在m_iLeftX/m_iLeftY中,并置m_bLeftDown为真,标识当前左键以及按下if (ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON){m_iLeftX = ea.getX();m_iLeftY = ea.getY();m_bLeftDown = true;}return false;}break;case osgGA::GUIEventAdapter::DRAG:{if (m_bLeftDown){int delX = ea.getX() - m_iLeftX;int delY = ea.getY() - m_iLeftY;m_vRotation[2] -= osg::DegreesToRadians(m_vRotateStep*delX);//得到左右旋转角度m_vRotation[0] += osg::DegreesToRadians(m_vRotateStep*delY);//得到上下旋转角度//下面几句保证了向下向上旋转的范围if (m_vRotation[0] <= 0){m_vRotation[0] = 0;}if (m_vRotation[0] >= osg::PI){m_vRotation[0] = osg::PI;}}}break;case osgGA::GUIEventAdapter::RELEASE:{if (ea.getButton() == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON){m_bLeftDown = false;}}break;default:break;}return false;  //代表事件还会向下传递,否则其他事件处理器不会再收到事件
}void CSouth::setStep(int delta_step)
{m_vStep += delta_step;if (m_vStep <= 0){m_vStep = 0;}
}//没有加上楼梯算法,加上的见下
//bool CSouth::changePosition(osg::Vec3 delta)
//{
//  //如果外部调用了m_node,需要接口做碰撞检测
//  if (m_node)
//  {
//      osg::Vec3 newPos = m_vPosition + delta;
//      osgUtil::IntersectVisitor iv;
//
//      osg::ref_ptr<osg::LineSegment> line = new osg::LineSegment(newPos, m_vPosition);
//      iv.addLineSegment(line.get());
//      m_node->accept(iv);
//      //判断是否碰到,如果没有碰到物体则移动,否则直接返回
//      if (!iv.hits())
//      {
//          m_vPosition += delta;
//      }
//      else
//      {
//          return false;
//      }
//  }
//
//
//  //外部不需要做碰撞检测
//  else
//  {
//      m_vPosition += delta;
//  }
//
//  return true;
//}//加上算楼梯算法,没加上的见上
bool CSouth::changePosition(osg::Vec3 delta)
{//如果外部调用了m_node,需要接口做碰撞检测if (m_node){osg::Vec3 newPos = m_vPosition + delta;//代表点2//代表上楼梯中线A,上取80m,下取1000mosg::Vec3 start = osg::Vec3(newPos.x(), newPos.y(), newPos.z() + 80);osg::Vec3 end = osg::Vec3(newPos.x(), newPos.y(), newPos.z() -1000);osg::ref_ptr<osgUtil::IntersectionVisitor> iv = new osgUtil::IntersectionVisitor;//碰撞检测类osg::ref_ptr<osgUtil::LineSegmentIntersector> ls = new osgUtil::LineSegmentIntersector(start, end);//可以取出结果集的线段osgUtil::LineSegmentIntersector::Intersections itersections;long height = newPos.z();iv->setIntersector(ls.get());m_node->accept(*(iv.get()));if (ls->containsIntersections()){itersections = ls->getIntersections();osgUtil::LineSegmentIntersector::Intersections::iterator iter = itersections.begin();height = iter->getLocalIntersectPoint().z() + 5;}else{return false; //如果无结果说明前面不存在楼梯,无法移动。因为上到80m下到1000m都无交点}//下面是看线段B与场景中物体是否有交点osg::Vec3 start2 = osg::Vec3(m_vPosition.x(), m_vPosition.y(), height);osg::Vec3 end2 = osg::Vec3(newPos.x(), newPos.y(), height);osgUtil::IntersectVisitor iv2;osg::ref_ptr<osg::LineSegment> line = new osg::LineSegment(start2, end2);iv2.addLineSegment(line.get());m_node->accept(iv2);if (!iv2.hits()){m_vPosition += delta;m_vPosition.set(m_vPosition.x(), m_vPosition.y(), height);}else{return false;}}//外部不需要做碰撞检测else{m_vPosition += delta;}return true;
}
void CSouth::setMnode(osg::Node* node)
{m_node = node;
}

main.cpp

int main()
{osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;osg::Group* root = new osg::Group;//root->addChild(createFloor(osg::Vec3(0, 0, 0), 200));root->addChild(CreateStair());//在场景放置一个楼梯用于碰撞检测root->addChild(createQuad());viewer->setSceneData(root);CSouth* cs = new CSouth;cs->setMnode(root);viewer->setCameraManipulator(cs);return viewer->run();
}

osg_操作器、碰撞检测、上楼梯篇相关推荐

  1. 改造layui-树(tree)组件的添加、编辑、删除操作(补充上一篇)

    这篇是用来补充上一篇:改造layui-树(tree)组件支持添加.编辑.删除的自定义(弹框)操作(https://blog.csdn.net/liona_koukou/article/details/ ...

  2. 如何减小电压跟随器输出电阻_气动操作器FBD5061SF-1蓝宇品牌安徽

    气动操作器FBD5061SF-1蓝宇品牌安徽 具备手/自动切换功能的操作器.一般连接在调节设备和执行器(阀门)之间. 自动方式时按调节输入信号控制阀门开度,手动时按仪表面板给定的操作量控制阀门开度. ...

  3. 数据与广告系列十二:接上一篇,见习算法工程师教程

    作者|黄崇远(题图:ssyer.com,CCO协议)  公号,数据虫巢(ID: blogchong) " 看完了这篇,你就是个见习级算法工程师了.你觉得可能吗?" 接上一篇< ...

  4. 如何实现新闻上一篇、下一篇的功能

    我们在做CMS内容管理系统的时候,经常会使用到在新闻详情页浏览上一篇.下一篇的功能,这个功能可以帮助用户在新闻详情页快速的方便的浏览其他的新闻,而不用返回到新闻列表页再点击,是个相当实用的功能.今天我 ...

  5. 蓝桥杯实战应用【赛题解析篇】-小白上楼梯(递归设计)(附python、C++和Java代码)

    问题描述 小白正在上楼梯,楼梯有n阶台阶,小白一次可以上1阶,2阶,3阶. 实现一个方法,计算小白有多少种上楼梯的方式. 输入输出 输出:台阶数量. 输出:多少种上楼梯的方式 例如:4阶楼梯 有7种方 ...

  6. 查询优化器内核剖析第一篇

    查询优化器内核剖析第一篇 查询优化器内核剖析第一篇 查询优化器内核剖析第二篇:产生候选执行计划&执行计划成本估算 查询优化器内核剖析第三篇:查询的执行与计划的缓存 & Hint提示 查 ...

  7. 在Vue中自制视频播放器(上)

    在Vue中自制视频播放器(上) 前言 初始化组件 开始/暂停按钮 停止按钮 静音按钮 视频播放时间 全屏按钮 源代码 前言 平时大家在浏览视频网站时,会发现各大视频网站都有自己的视频控制组件,虽然浏览 ...

  8. java按顺序售票方法_java_Java代码实践12306售票算法(二),周五闲来无事,基于上一篇关 - phpStudy...

    Java代码实践12306售票算法(二) 周五闲来无事,基于上一篇关于浅析12306售票算法(java版)理论,进行了java编码实践供各位读者参考(以下为相关代码的简单描述) 1.订票工具类 1.1 ...

  9. Android 中LayoutInflater(布局加载器)之介绍篇

    本文出自博客Vander丶CSDN博客,如需转载请标明出处,尊重原创谢谢 博客地址:http://blog.csdn.net/l540675759/article/details/78099358 前 ...

最新文章

  1. Matplotlib绘图双纵坐标轴设置及控制设置时间格式
  2. pip导包CalledProcessError: Command '('lsb_release', '-a')'异常处理
  3. 科大星云诗社动态20210318
  4. Ceph分布式存储实战2.4 本章小结
  5. VS2010+WinXP+MFC程序 无法定位程序输入点于动态链接库
  6. CF思维联系– CodeForces - 991C Candies(二分)
  7. Windows7上安装TensorFlow——基于Docker镜像
  8. 多个cpp文件生成so_boostpython:从多个.cpp文件创建一个模块(.so)
  9. 使用Selenium或WebDriver测试GWT应用
  10. JDK 伪异步编程(线程池)
  11. 可能是全网最全的 Java 日志框架适配、冲突解决方案
  12. POI操作EXCEL2007,报javax.xml.stream.XMLEventFactory.newFactory()错误!
  13. python3_configparser模块详解
  14. HIVE存储(四)ORCFile
  15. (转)万万没想到,无人车其实是个劳动密集型产业
  16. Python坦克大战(一):素材准备
  17. ubuntu vmplayer安装vmtool
  18. 外地人排北京新能源指标需要什么条件?需要摇号吗?
  19. HDU-1728-逃离迷宫
  20. 2018-《此生未完成》于娟

热门文章

  1. GNS3安装和使用详细图文教程,避免各种烦人报错
  2. vmware装win7镜像无法装vmtools(官网补丁)
  3. [BUUCTF]REVERSE——reverse2
  4. mysql hy000 2013_ERROR 2013 (HY000): Lost connection to MySQL server
  5. HT32F52352软件安装、环境搭建
  6. synchronized、volatile的区别
  7. 欧美风企业宣传PPT模板
  8. 解决新手引导图片被导航栏遮盖住得问题
  9. 浏览器from memory cache 和 from disk cache
  10. 服务器内存2rx4是什么意思_内存上的2rx8、1rx8、2rx4什么意思