OSG开发笔记(二十四):OSG漫游之平移与转向

若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/98964269

目录

前言

Demo工程实现功能

Demo运行效果

操作器概述

初始化默认位置

移动位置

实现简单的漫游器

漫游器代码

MyCameraMainpulator.h

MyCameraMainpulator.cpp

OSG 3.4.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漫游之平移、转向和低抬头

 

前言

       80后典型的使用三维技术的游戏代表作就是CS,CS中可以使用WSAD移动,移动的过程就是漫游。

 

Demo工程实现功能

  • WSAD:向前后左右移动
  • QE/方向键左右:向左右移动视角
  • 方向键上下:向上下移动视角(抬头、低头)

 

Demo运行效果

        

        

         

 

操作器概述

       在场景中有一个重要的概念,漫游。漫游就是在场景中移动,漫游可以按照用户的要求漫游也可以按照预先的计划漫游(路线)。在之前的开发中,都是用的是OSG自带的操作器Trackball,大众而好用,满足基本需求。但是无法实现CS中的漫游方式(移动还有碰撞等等)。

       场景的核心管理类是viewer,想要自定义漫游则必须相应事件,比如鼠标动了,场景也在动。响应事件的类是osgGA::GUIEventHandler,实现漫游使用的响应事件的类是事件响应类的子类,类名osgGA::MatrixManipulator,控制漫游实际就是矩阵变换,这个类有一些设置矩阵的公共接口,通过接口控制viewer了。OSG自带的几个操作器,操作都相同,漫游的主要流程如下:

        

        在1时,使用setCameraManipulator设置操作器;

        在2时,每次更新场景都会调用操作器获取矩阵变换;

        在3时,每次接收到消息都会触发操作器的handle事件;

        操作器必须从osgGA:MatrixManipulator派生而来,而该类提供的接口如下:

virtual void setByMatrix(const osg::Matrixd &matrix) = 0;
virtual void setByInverseMatrix(const osg::Matrixd &matrix) = 0;
// 当场景更新时,会被管理类调用
virual osg::Matrixd getMatrix() const = 0;
// 当场景更新时,会被管理类调用
virtual osg::Matrixd getInverseMatrix() const = 0;

        以上四个接口可以向viewer传递矩阵的相关信息。

        然后通过handle接口对消息进行处理。

 

初始化默认位置

        初始化操作其实,需要带上当前视口默认的操作位置与旋转矩阵。

        

        由上图,最值得注意的是视口摄像机的默认方向为向下,所以需要绕X轴旋转90度调整视口方向。

 

移动位置

        

        如上图,若向右旋转45度后,那么走一段距离,需要进行三角函数计算,得到两个轴上的位移,然后对原位置进行修改。

 

实现简单的漫游器

步骤一:继承自osgGA::CameraMainpulator

步骤二:重新实现4个纯虚函数

步骤三:设置初始位置、旋转角度、移动步长、旋转步长

步周四:处理消息函数handle

 

漫游器代码

MyCameraMainpulator.h

#ifndef MYCAMERAMAINPULATOR_H
#define MYCAMERAMAINPULATOR_H

#include <osgGA/CameraManipulator>
#include <osgGA/GUIActionAdapter>
#include <osgGA/GUIEventAdapter>

class MyCameraMainpulator : public osgGA::CameraManipulator
{
public:
    MyCameraMainpulator();
    ~MyCameraMainpulator();

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);

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轴当前旋转角度
};

#endif // MYCAMERAMAINPULATOR_H

MyCameraMainpulator.cpp

#include "MyCameraMainpulator.h"
#include <QDebug>
#include "osg/Math"

MyCameraMainpulator::MyCameraMainpulator()
    : _originAngleX(90.0f),
      _originAngleY(0.0f),
      _originAngleZ(0.0f),
      _offsetAngleX(0.0f),
      _offsetAngleY(0.0f),
      _offsetAngleZ(0.0f)
{
    // 使用漫游器的初始化位置
    _position = osg::Vec3(  -0.0f, -5.0f, 0.0f);
    _rotation = osg::Vec3( osg::DegreesToRadians(_originAngleX + _offsetAngleX),
                           osg::DegreesToRadians(_originAngleY + _offsetAngleY),
                           osg::DegreesToRadians(_originAngleZ + _offsetAngleZ));
    _moveStep = 0.01f;
    _rotateStep = 0.1f;
}

MyCameraMainpulator::~MyCameraMainpulator()
{

}

void MyCameraMainpulator::setByMatrix(const osg::Matrixd &matrix)
{

}

void MyCameraMainpulator::setByInverseMatrix(const osg::Matrixd &matrix)
{
    computeHomePosition();
}

osg::Matrixd MyCameraMainpulator::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 MyCameraMainpulator::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 MyCameraMainpulator::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us)
{
    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:
            _position[1] += _moveStep * cos(osg::DegreesToRadians(-_offsetAngleZ));
            _position[0] += _moveStep * sin(osg::DegreesToRadians(-_offsetAngleZ));
            break;
        case osgGA::GUIEventAdapter::KEY_S:
            _position[1] -= _moveStep * cos(osg::DegreesToRadians(-_offsetAngleZ));
            _position[0] -= _moveStep * sin(osg::DegreesToRadians(-_offsetAngleZ));
            break;
        case osgGA::GUIEventAdapter::KEY_A:
            _position[0] -= _moveStep * cos(osg::DegreesToRadians(-_offsetAngleZ));
            _position[1] += _moveStep * sin(osg::DegreesToRadians(-_offsetAngleZ));
            break;
        case osgGA::GUIEventAdapter::KEY_D:
            _position[0] += _moveStep * cos(osg::DegreesToRadians(-_offsetAngleZ));
            _position[1] -= _moveStep * sin(osg::DegreesToRadians(-_offsetAngleZ));
            break;
        case osgGA::GUIEventAdapter::KEY_Up:
            _offsetAngleX += _rotateStep;
            _rotation[0] = osg::DegreesToRadians(_originAngleX + _offsetAngleX);
            break;
        case osgGA::GUIEventAdapter::KEY_Down:
            _offsetAngleX -= _rotateStep;
            _rotation[0] = osg::DegreesToRadians(_originAngleX + _offsetAngleX);
            break;
        default:
            break;
        }
        qDebug() << "position: " << _position.x() << "," << _position.y() << "," << _position.z()
                 << "rotation: " << _rotation.x() << "," <<  _rotation.y() << "," <<  _rotation.z();
        break;
    default:
        break;
    }
    return true;
}

 

OSG 3.4.0 中的漫游器概览

       漫游器在osgGA库中实现,这个库主要是用来处理用户与三维场景的交互(包括鼠标、键盘、手势、操纵杆等),之前我们设置是可以添加消息处理的,详情见《OSG开发笔记(十四):OSG交互》,在添加的消息类中处理hand中返回true,则消息不会传递到漫游器当中去,返回false则消息会传到漫游器中。

       消息处理类中处理与漫游器处理的区别,消息处理中需要获取osg::Viewer直接对模型进行操作,而漫游器中是直接操作矩阵。

       在OSG3.4.0版本中的漫游器类型,如下图:

       

       设置纯漫游器的效果如下表:

序号

漫游器

详细描述

效果

0

不使用

没有漫游器则没有视图

1

osgGA::CameraManipulator

抽象类,无法使用

2

osgGA::StandardManipulator

抽象类,无法使用

3

osgGA::OrbitManipulator

鼠标控制,绕X轴只能翻转180,持续旋转

4

osgGA::TrackballManipulator

常用的漫游方式,基于轨迹球理论进行设计。鼠标控制,全方位旋转,持续旋转

同上

5

osgGA::MultiTouchTrackballManipulator

鼠标控制,全方位旋转,持续旋转,触屏未测

同上

6

osgGA::NodeTrackerManipulator

鼠标控制,全方位旋转,持续旋转,触屏未测

同上

7

osgGA::TerrainManipulator

固定绕一个点动,鼠标控制,全方位旋转,持续旋转,触屏未测

8

osgGA::FirstPersonManipulator

鼠标移动视角,持续旋转

9

osgGA::FlightManipulator

模拟飞机飞行的漫游方式

先整中间,鼠标放入窗口飞行

10

osgGA::AnimationPathManipulator

根据指定的路径自动执行场景的漫游

11

osgGA::SphericalManipulator

模拟球面浏览的漫游方式。鼠标控制,绕X轴只能翻转180,持续旋转

12

osgGA::CameraViewSwitchManipulator

可以切换相机视角的漫游器

13

osgGA::DriveManipulator

模拟汽车驾驶的漫游方式

14

osgGA::KeySwitchMatrixManipulator

测试挂,需要其他配合

 

15

osgGA::UFOManipulator

模拟UFO飞行漫游方式

16

osgGA::StateSetManipulator

非cameraManipulator子类

 

 


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

发布了228 篇原创文章 · 获赞 241 · 访问量 40万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览