OSG开发笔记(二十六):OSG漫游之上下楼梯

欢迎技术交流和帮助,提供IT相关服务,索要源码请联系博主QQ:21497936,若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936本文章博客地址:目录前言Demo效果画楼梯代码漫游器行走碰撞逻辑调整漫游器上楼梯关键代码初始化场景代码Stairs代码UpDownStairsCameraMainpulator.hStairs代码UpDow...

OSG开发笔记(二十六):OSG漫游之上下楼梯

欢迎技术交流和帮助,提供IT相关服务,索要源码请联系博主QQ: 21497936,若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:

目录

前言

Demo效果

画楼梯代码

漫游器

行走碰撞逻辑调整

漫游器上楼梯

关键代码

初始化场景代码

Stairs代码UpDownStairsCameraMainpulator.h

Stairs代码UpDownStairsCameraMainpulator.cpp

工程模板:对应版本号1.23.0

OSG三维开发专栏

OSG开发笔记(一):OSG介绍、编译

OSG开发笔记(二):OSG帮助文档编译

OSG开发笔记(三):OSG使用osgQt嵌入Qt应用程序

OSG开发笔记(四):OSG不使用osgQt重写类嵌入Qt应用程序》:

OSG开发笔记(五):OSG场景理解与基础类概述

OSG开发笔记(六):OSG内存管理

OSG开发笔记(七):OSG复现OpenGL入门示例和OSG坐标系

OSG开发笔记(八):OSG模型文件存储与读取

OSG开发笔记(九):OSG模型的基本操作之添加/删除、显示/隐藏、开关节点开/关》:

OSG开发笔记(十):OSG模型的变换之平移、旋转和缩放

OSG开发笔记(十一):OSG渲染状态与2D纹理映射

OSG开发笔记(十二):OSG基本几何图形、内置几何类型

OSG开发笔记(十三):OSG三维纹理映射(体渲染)

OSG开发笔记(十四):OSG交互

OSG开发笔记(十五):OSG光照

OSG开发笔记(十六):OSG视口、相机和视点

OSG开发笔记(十七):OSG中的相机移动

OSG开发笔记(十八):OSG鼠标拾取pick、拽托球体以及多光源

OSG开发笔记(十九):OSG文字显示

OSG开发笔记(二十):OSG使用HUD显示文字

OSG开发笔记(二十一):OSG使用HUD绘制图形以及纹理混合模式

OSG开发笔记(二十二):OSG场景背景

OSG开发笔记(二十三):Qt使用QOpenGLWidget渲染OSG和地球仪

OSG开发笔记(二十四):OSG漫游之平移、转向和低抬头

OSG开发笔记(二十五):OSG漫游之CS移动、碰撞检测与跳跃

OSG开发笔记(二十六):OSG漫游之上下楼梯

OSG开发笔记(二十七):OSG路径漫游之录制播放固定路径动画

OSG开发笔记(二十八):OSG模型固定路径动画

� 持续补充中…

� � � � OSG开发笔记(二十六):OSG漫游之上下楼梯

前言

������ 前面实现了碰撞,比如掉下去摔死,前面有障碍物不能走动,跳跃等等,本篇写一个上下楼算法。

Demo效果

� � � ��

Demo运行程序下载:

������ https://download.csdn.net/download/qq21497936/11575952

画楼梯代码

������ 将多个立方体做成转换对象,然后偏移添加进去。

� � � �

� � � �

漫游器

������ 复制上一章的CS漫游器,对几个细节进行调整优化。

行走碰撞逻辑调整

������ 正常的行走碰撞不可能完全贴合地面,存在比如0.0001的距离,足够小的距离则可以等于没有距离,但是又没有碰撞到,而CS漫游器的时候我们设置的是0.1的距离,现在单独设置离地面垂直距离最小距离为0.0001,截取相关的代码如下:

� � � ��

漫游器上楼梯

������ 这里涉及到精细碰撞,上楼梯主要是垂直的,上楼梯逻辑如下:

  • 步骤一:先判断物体底部移动是否碰撞,有碰撞进行下一步;
  • 步骤二:在允许上的高度z值判断物体是否碰撞,没有碰撞进行下一步;
  • 步骤三:设置楼梯高度然后向前移动(准确的应该要获取前面底部碰撞但是高度z没碰撞的物体的盒子上边距离,然后将其设置为物体的);

������ 以上流程就是上楼梯算法步骤,下楼梯则无需,本身我们就有下坠机制。

� � � �

关键代码初始化场景代码
osg::ref_ptr<osg::Node> OsgWidget::getUpDownStairsAndManipulator(){ // 隐藏按键面板 ui->groupBox_pannel->setVisible(false); osg::ref_ptr<osg::Group> pGroup = new osg::Group; // 首先画个地板 {  osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;  // 地板格子长、宽、行、列  float dx = 1.0f;  float dy = 1.0f;  int rows = 20;  int cols = 20;  osg::Vec3 vec3center(0.0f - dx * rows / 2, 0.0f - dx * cols / 2, 0.0f);  // 顶点  osg::Vec3Array *pVec3Array = new osg::Vec3Array;  for(int index = 0; index <= rows; index  )  {for(int index2 = 0; index2 <= cols; index2  ){ pVec3Array->push_back(osg::Vec3(index2 * dx, index * dy, 0)vec3center);}  }  // 颜色  osg::Vec4Array *pVec4ColorArray = new osg::Vec4Array;  pVec4ColorArray->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));  pVec4ColorArray->push_back(osg::Vec4(0.0f, 0.0f, 0.0f, 1.0f));  // 索引(使用索引,之前的demo没有使用过,此源码第一次使用)之处  osg::UIntArray * pCoordIndices = new osg::UIntArray;  osg::UIntArray * pColorIndices = new osg::UIntArray;  for(int index = 0; index < rows; index  )  {for(int index2 = 0; index2 < cols; index2  ){ // 顶点索引 pCoordIndices->push_back((index2 )(index ) * (cols1)); pCoordIndices->push_back((index21)(index ) * (cols1)); pCoordIndices->push_back((index21)(index1) * (cols1)); pCoordIndices->push_back((index2 )(index1) * (cols1)); pColorIndices->push_back(((index2)(index1) * (cols 1) ) % pVec4ColorArray->size());}  }  // 法线  osg::Vec3Array * pNormal = new osg::Vec3Array;  pNormal->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));  // 图形(支持索引的需要使用deprecated_osg: :Geometry)  deprecated_osg::Geometry * pGeometry = new deprecated_osg::Geometry;  pGeometry->setVertexArray(pVec3Array);  pGeometry->setVertexIndices(pCoordIndices);  pGeometry->setColorArray(pVec4ColorArray);  pGeometry->setColorIndices(pColorIndices);  pGeometry->setColorBinding(deprecated_osg::Geometry::BIND_PER_PRIMITIVE);  pGeometry->setSecondaryColorArray(pVec4ColorArray);  pGeometry->setSecondaryColorIndices(pColorIndices);  pGeometry->setSecondaryColorBinding(deprecated_osg::Geometry::BIND_PER_PRIMITIVE);  pGeometry->setNormalArray(pNormal);  pGeometry->setNormalBinding(deprecated_osg::Geometry::BIND_OVERALL);  pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, pCoordIndices->size()));  osg::StateSet *pStateSet = pGeometry->getOrCreateStateSet();  pStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);  pStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);  pGeode->addDrawable(pGeometry);  pGroup->addChild(pGeode); } // 画几个立方体,当作楼梯 {  int rows = 20;  int cols = 20;  // 绘制立方体  osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;  // 精细度  osg::ref_ptr<osg::TessellationHints> pHints = new osg::TessellationHints;  pHints->setDetailRatio(0.5);  // 颜色  // 绘制几何体  float width = 0.25f;  osg::ref_ptr<osg::ShapeDrawable> pShapeDrawable = new osg::ShapeDrawable(  new osg::Box(osg::Vec3f(-width * rows * 20.25width2 * width, 0, width / 2),width * 2,width * 2,width),  pHints.get());  pGeode->addDrawable(pShapeDrawable.get());  osg::StateSet *pStateSet = pGeode->getOrCreateStateSet();  pStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);  pStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);  // 关闭光照开启深度测试  for(int index = 0; index < rows; index  )  {for(int index2 = 0; index2 < cols; index2  ){ osg::ref_ptr<osg::MatrixTransform> pTrans = new osg::MatrixTransform; pTrans->addChild(pGeode); osg::Matrix matrix = pTrans->getMatrix(); matrix *= osg::Matrix::translate((width * indexindex2 * rows * width)*2, 0, width * indexindex2 * rows * width); pTrans->setMatrix(matrix); pGroup->addChild(pTrans.get());}  } } // 设置漫游器 {  UpDownStairsCameraMainpulator *pUpDownStairsCameraMainpulator = new UpDownStairsCameraMainpulator;  pUpDownStairsCameraMainpulator->setHitsNode(pGroup.get());  pUpDownStairsCameraMainpulator->setOsgWidget(this);  _pViewer->setCameraManipulator(pUpDownStairsCameraMainpulator); } return pGroup.get();}
Stairs代码UpDownStairsCameraMainpulator.h
#ifndef UPDOWNSTAIRSCAMERAMAINPULATOR_H#define UPDOWNSTAIRSCAMERAMAINPULATOR_H#include <osgGA/CameraManipulator>#include <osgGA/GUIActionAdapter>#include <osgGA/GUIEventAdapter>#include <QObject>class OsgWidget;class UpDownStairsCameraMainpulator : public osgGA::CameraManipulator, public QObject{public: UpDownStairsCameraMainpulator(); ~UpDownStairsCameraMainpulator();public: virtual void setByMatrix(const osg::Matrixd& matrix);  // 设置相机的位置姿态矩阵 virtual void setByInverseMatrix(const osg::Matrixd& matrix); // 设置相机的视图矩阵 virtual osg::Matrixd getMatrix() const; // 获取相机的姿态矩阵 virtual osg::Matrixd getInverseMatrix() const;// 获取相机的视图矩阵 virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us);public: void setHitsNode(osg::Node *pNode); void setOsgWidget(OsgWidget *pOsgWidget);protected: bool isHits(osg::Vec3f oldPos, osg::Vec3 newPos); void reset();protected: void timerEvent(QTimerEvent *event);private: osg::Vec3 _position;  // 视点当前位置 osg::Vec3 _rotation;  // 朝向 float _moveStep;// 移动步长5 float _rotateStep; // 旋转步长 float _originAngleX;  // X轴初始化时偏移角度 float _originAngleY;  // Y轴初始化时偏移角度 float _originAngleZ;  // Z轴初始化时偏移角度 float _offsetAngleX;  // X轴当前旋转角度 float _offsetAngleY;  // Y轴当前旋转角度 float _offsetAngleZ;  // Z轴当前旋转角度 float _radius;  // 将视口的当前物体认为是一个球 float _verticalSpace; // 间距,踩地面上实际碰撞的最小间距 osg::Node *_pNode; bool _canJump; OsgWidget *_pOsgWidget;};#endif // MYCAMERAMAINPULATOR_H
Stairs代码UpDownStairsCameraMainpulator.cpp
#include "UpDownStairsCameraMainpulator.h"#include <QDebug>#include "osg/Math"#include "osg/LineSegment"#include "OsgWidget.h"UpDownStairsCameraMainpulator::UpDownStairsCameraMainpulator() :  QObject(0),_originAngleX(90.0f),_originAngleY(0.0f),_originAngleZ(0.0f),_offsetAngleX(0.0f),_offsetAngleY(0.0f),_offsetAngleZ(0.0f),_radius(0.5f),_pNode(0),_verticalSpace(0.0001),_canJump(false){ // 使用漫游器的初始化位置 _position = osg::Vec3(-9.5f, 0.0f, _radius_verticalSpace); _offsetAngleZ = -90.0f; _rotation = osg::Vec3( osg::DegreesToRadians(_originAngleX_offsetAngleX),osg::DegreesToRadians(_originAngleY_offsetAngleY),osg::DegreesToRadians(_originAngleZ_offsetAngleZ)); _moveStep = 0.08f; _rotateStep = 2.0f; startTimer(15);}UpDownStairsCameraMainpulator::~UpDownStairsCameraMainpulator(){}void UpDownStairsCameraMainpulator::setByMatrix(const osg::Matrixd &matrix){}void UpDownStairsCameraMainpulator::setByInverseMatrix(const osg::Matrixd &matrix){ computeHomePosition();}osg::Matrixd UpDownStairsCameraMainpulator::getMatrix() const{ osg::Matrixd mat; mat.makeTranslate(_position); return osg::Matrixd::rotate(_rotation.x(), osg::X_AXIS,  _rotation.y(), osg::Y_AXIS,  _rotation.z(), osg::Z_AXIS) * mat;}osg::Matrixd UpDownStairsCameraMainpulator::getInverseMatrix() const{ osg::Matrixd mat; mat.makeTranslate(_position); return osg::Matrixd::inverse(osg::Matrixd::rotate(_rotation.x(), osg::X_AXIS,_rotation.y(), osg::Y_AXIS,_rotation.z(), osg::Z_AXIS) * mat);}bool UpDownStairsCameraMainpulator::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us){ float offsetX = 0.0f; float offsetY = 0.0f; float offsetZ = 0.0f; osg::Vec3f newPosition; osg::Vec3f newPositionBottom; osg::Vec3f positionBottom; switch (ea.getEventType()) { case osgGA::GUIEventAdapter::KEYDOWN:  switch (ea.getKey()) {  case osgGA::GUIEventAdapter::KEY_E:  case osgGA::GUIEventAdapter::KEY_Right:_offsetAngleZ = _offsetAngleZ - _rotateStep;_rotation[2] = osg::DegreesToRadians(_originAngleZ_offsetAngleZ);break;  case osgGA::GUIEventAdapter::KEY_Q:  case osgGA::GUIEventAdapter::KEY_Left:_offsetAngleZ = _offsetAngleZ_rotateStep;_rotation[2] = osg::DegreesToRadians(_originAngleZ_offsetAngleZ);break;  case osgGA::GUIEventAdapter::KEY_W:offsetY = _moveStep * cos(osg::DegreesToRadians(-_offsetAngleZ));offsetX = _moveStep * sin(osg::DegreesToRadians(-_offsetAngleZ));newPosition = _positionosg::Vec3f(offsetX, offsetY, offsetZ);positionBottom = _position - osg::Vec3f(0, 0, _radius);newPositionBottom = newPosition - osg::Vec3f(0, 0, _radius);if(!isHits(positionBottom, newPositionBottom)){ _position = newPosition;}else if(!isHits(_position, newPosition)){ _position[2]  = 0.5f;}break;  case osgGA::GUIEventAdapter::KEY_S:offsetY = _moveStep * cos(osg::DegreesToRadians(-_offsetAngleZ));offsetX = _moveStep * sin(osg::DegreesToRadians(-_offsetAngleZ));newPosition = _position - osg::Vec3f(offsetX, offsetY, offsetZ);positionBottom = _position - osg::Vec3f(0, 0, _radius);newPositionBottom = newPosition - osg::Vec3f(0, 0, _radius);if(!isHits(positionBottom, newPositionBottom)){ _position = newPosition;}else if(!isHits(_position, newPosition)){ _position[2]  = 0.5f;}break;  case osgGA::GUIEventAdapter::KEY_A:offsetX = -_moveStep * cos(osg::DegreesToRadians(-_offsetAngleZ));offsetY =  _moveStep * sin(osg::DegreesToRadians(-_offsetAngleZ));newPosition = _positionosg::Vec3f(offsetX, offsetY, offsetZ);positionBottom = _position - osg::Vec3f(0, 0, _radius);newPositionBottom = newPosition - osg::Vec3f(0, 0, _radius);if(!isHits(positionBottom, newPositionBottom)){ _position = newPosition;}else if(!isHits(_position, newPosition)){ _position[2]  = 0.5f;}break;  case osgGA::GUIEventAdapter::KEY_D:offsetX =  _moveStep * cos(osg::DegreesToRadians(-_offsetAngleZ));offsetY = -_moveStep * sin(osg::DegreesToRadians(-_offsetAngleZ));newPosition = _positionosg::Vec3f(offsetX, offsetY, offsetZ);positionBottom = _position - osg::Vec3f(0, 0, _radius);newPositionBottom = newPosition - osg::Vec3f(0, 0, _radius);if(!isHits(positionBottom, newPositionBottom)){ _position = newPosition;}else if(!isHits(_position, newPosition)){ _position[2]  = 0.5f;}break;  case osgGA::GUIEventAdapter::KEY_Up:if(_offsetAngleX > 20){ break;}_offsetAngleX  = _rotateStep;_rotation[0] = osg::DegreesToRadians(_originAngleX_offsetAngleX);break;  case osgGA::GUIEventAdapter::KEY_Down:if(_offsetAngleX < -20){ break;}_offsetAngleX -= _rotateStep;_rotation[0] = osg::DegreesToRadians(_originAngleX_offsetAngleX);break;  case osgGA::GUIEventAdapter::KEY_Space://if(_position[2] >= _radius && _position[2] <= _radius_moveStep)if(_canJump){ _position[2]  = 1.0f;}_canJump = false;break;  default:break;  }  break; default:  break; } return true;}void UpDownStairsCameraMainpulator::setHitsNode(osg::Node *pNode){ _pNode = pNode;}bool UpDownStairsCameraMainpulator::isHits(osg::Vec3f oldPos, osg::Vec3 newPos){ bool ret = false; if(_pNode == 0) {  return ret; } // osg3.4.0 类 osgUtil::IntersectionVisitor已经细化,此处用 osg::ref_ptr<osgUtil::LineSegmentIntersector> pLs = new osgUtil::LineSegmentIntersector(oldPos, newPos); osg::ref_ptr<osgUtil::IntersectionVisitor> pIv = new osgUtil::IntersectionVisitor(pLs); // 碰撞检测 _pNode->accept(*pIv); if(pLs->containsIntersections()) {//  qDebug() << "hit";  ret = true; }else{  ret = false; } return ret;}void UpDownStairsCameraMainpulator::reset(){ _originAngleX = 90.0f; _originAngleY = 0.0f; _originAngleZ = 0.0f; _offsetAngleX = 0.0f; _offsetAngleY = 0.0f; _offsetAngleZ = -90.0f;  // 使用漫游器的初始化位置 _position = osg::Vec3(-9.5f, 0.0f, _radius_verticalSpace); _rotation = osg::Vec3( osg::DegreesToRadians(_originAngleX_offsetAngleX), osg::DegreesToRadians(_originAngleY_offsetAngleY), osg::DegreesToRadians(_originAngleZ_offsetAngleZ)); if(_pOsgWidget) {  _pOsgWidget->update(); }}void UpDownStairsCameraMainpulator::timerEvent(QTimerEvent *event){ // 往下offsetX = -_moveStep * cos(osg::DegreesToRadians(-_offsetAngleZ)); float offsetX = 0.0f; float offsetY = 0.0f; float offsetZ = 0.0f; offsetZ = -_moveStep - _radius; osg::Vec3f newPosition = _positionosg::Vec3f(offsetX, offsetY, offsetZ); if(!isHits(_position, newPosition)) {  newPosition[2]  = _radius;  _position = newPosition;  if(_position[2] < -10.0f)  {reset();  }  if(_pOsgWidget)  {_pOsgWidget->update();  } }else{  if(newPosition[2] == 0.0_verticalSpace)  {  }else{newPosition[2] = _verticalSpace;_pOsgWidget->update();  }  _canJump = true; }}void UpDownStairsCameraMainpulator::setOsgWidget(OsgWidget *pOsgWidget){ _pOsgWidget = pOsgWidget;}

工程模板:对应版本号1.23.0

� � � � 对应版本号1.23.0

原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:

源文地址:https://www.guoxiongfei.cn/csdn/7968.html