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

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

目录

前言

交互概述

交互实现方式与步骤

交互动作

模型多种类型动作的理解

代码

地球代码

事件代码

操作过程

工程模板:对应版本号1.11.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交互

 

前言

       交互一般指鼠标和键盘、也可以是触摸等,在地球的基础上增加方向键控制旋转、鼠标控制显示、缩放和重置模型状态。

 

交互概述

        操作三维场景主要是操作三维场景数据,场景数据主要由viewer负责进行渲染,要得到数据可以使用viewer->getSceneData()就可以了。

        Viewer主要功能是控制场景,是场景的核心类。

        Viewer中有addEventHandler就是专门添加时间处理器相应交互动作的(鼠标和键盘),可以自己写事件处理器,对事件进行处理。

       OSG开发笔记(十四):OSG交互_第1张图片

        事件类型有很多,一个viewer可以相应ABCD等等多个事件,一个事件也可以拦截事件,也就是A处理完后给BCD处理,也可以拦截住使BCD收不到事件。

        存在事件,必然存在事件参数,给事件A传递参数,不必非要使用viewer进行处理,可以把viewer当参数传递进去。

 

交互实现方式与步骤

        本次介绍的方式是非回调方式,继承GUI事件类并重写虚函数即可。

        交互的实现方式是继承GUI事件类,然后重写其虚函数,步骤如下:

  • 步骤一:继承osgGA::GUIEventHandler;
  • 步骤二:重写虚函数handler,在里面重写事件;

        此处有三个虚函数,视作A1、A2、A3三个虚函数

OSG开发笔记(十四):OSG交互_第2张图片

       我们只需重载A3,这里的消息传递顺序是:

先传递给A1,此处看不到A1源码,按照测试结果,逻辑关系应该是A1调用了A2,A2调用A3。

 

交互动作

       在之前的地球上添加事件:

  • 方向键左:地球向左旋转
  • 方向键右:地球向右旋转
  • 方向键上:地球向上旋转
  • 方向键下:地球向下旋转
  • 鼠标滚轮向上:地球放大
  • 鼠标滚轮向下:地球缩小
  • 鼠标点击右键:地球显示
  • 鼠标点击左键:地球隐藏
  • 鼠标点击中间:地球显示、地球恢复原始角度、地球恢复原始大小

 

模型多种类型动作的理解

       渲染效果有渲染效果的类节点,变幻有变换的类节点,开关节点有开关节点的类节点,一个结点要实现多种的类型的,那就需要创建对应类型的结点,一层一层包裹起来,如下面的地球代码,既要实现变换又要实现显示隐藏所以需要创建3种类型的结点,第一种是模型(几何体)、第二种是变换(移动、缩放、旋转)、第三种是开关(显示、隐藏)。

       地球实现原理:开关节点中加入变换节点,变换节点加入图形几何节点。

 

代码

地球代码

osg::ref_ptr OsgWidget::getEarthSphiereAndKeyEvent()
{
    // 该结点是为了开关
    osg::ref_ptr pSwitch = new osg::Switch;
    // 该结点时为了变换
    osg::ref_ptr pTrans = new osg::MatrixTransform;
#if 1
    {
        // 绘制球体
        // 步骤一:绘制几何类型(几何体)
        osg::ref_ptr pGeode = new osg::Geode;
        qreal radius = 1.0;
        pGeode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0, 0, 0), radius)));
        // 步骤二:加载图片添加纹理
        osg::ref_ptr pImage;
        pImage = osgDB::readImageFile("D:/qtProject/osgDemo/osgDemo/modules/osgWidget/image/earth.bmp");
        osg::ref_ptr pTexture2D = new osg::Texture2D;
        pTexture2D->setImage(pImage.get());
        // 步骤三:渲染设置
        osg::ref_ptr pStateSet = pGeode->getOrCreateStateSet();
        pStateSet->setTextureAttribute(0, pTexture2D.get());
        pStateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
        pGeode->setStateSet(pStateSet);
        pTrans->addChild(pGeode);
        // 步骤四:添加事件管理器
        _pViewer->addEventHandler(new MyUserEventHandler);
    }
#endif
    pSwitch->addChild(pTrans);
    return pSwitch.get();
}

事件代码

MyUserEventHandler.h

#ifndef MYUSEREVENTHANDLER_H
#define MYUSEREVENTHANDLER_H

#include 
#include 

class MyUserEventHandler : public osgGA::GUIEventHandler
{

public:
    MyUserEventHandler();

public:
    /** Handle event. Override the handle(..) method in your event handlers to respond to events. */
//    virtual bool handle(osgGA::Event* event, 
//                     osg::Object* pObject, osg::NodeVisitor* pNodeVisitor);

    /** Handle events, return true if handled, false otherwise. */
//    virtual bool handle(const osgGA::GUIEventAdapter& guiEventAdapter,
//                     osgGA::GUIActionAdapter& guiActionAdapter, 
//                     osg::Object* pObject, osg::NodeVisitor* pNodeVisitor);

    /** Deprecated, Handle events, return true if handled, false otherwise. */
virtual bool handle(const osgGA::GUIEventAdapter& guiEventAdapter,
 osgGA::GUIActionAdapter& guiActionAdapter);

private:
    float _scale = 1.0f;  // 保存当前相对于原始比例的缩放系数
};

#endif // MYUSEREVENTHANDLER_H

MyUserEventHandler.cpp

bool MyUserEventHandler::handle(const osgGA::GUIEventAdapter 
                                &guiEventAdapter, osgGA::GUIActionAdapter &guiActionAdapter)
{
    bool flag = false;
    // 获取viwerer
    osg::ref_ptr pViewer
            = dynamic_cast(&guiActionAdapter);
    if(!pViewer)
    {
        return false;
    }
    osg::ref_ptr pSwitch = pViewer->getSceneData()->asSwitch();
    if(!pSwitch)
    {
        return false;
    }
    osg::ref_ptr pTransform = pSwitch->getChild(0)->asTransform();
    if(!pTransform)
    {
        return false;
    }
    osg::ref_ptr pTrans = pTransform->asMatrixTransform();
    if(!pTrans)
    {
        return false;
    }
    osg::Matrix matrix = pTrans->getMatrix();
    switch (guiEventAdapter.getEventType())
    {
    case osgGA::GUIEventAdapter::EventType::KEYDOWN:
        switch (guiEventAdapter.getKey())               // 左右上下 ADWS
        {
            case osgGA::GUIEventAdapter::KEY_Left:      // 左方向键-向左旋转1度
            case osgGA::GUIEventAdapter::KEY_A:         // A键-向左旋转1度
                matrix *= osg::Matrix::rotate(osg::DegreesToRadians(-1.0), 0, 0, 1);
                pTrans->setMatrix(matrix);
                flag = true;
                break;
            case osgGA::GUIEventAdapter::KEY_Right:     // 右方向键-向右旋转1度
            case osgGA::GUIEventAdapter::KEY_D:         // D键-向右旋转1度
                matrix *= osg::Matrix::rotate(osg::DegreesToRadians(1.0), 0, 0, 1);
                pTrans->setMatrix(matrix);
                flag = true;
                break;
            case osgGA::GUIEventAdapter::KEY_Up:        // 上方向键-向上旋转1度
            case osgGA::GUIEventAdapter::KEY_W:         // W键-向上旋转1度
                matrix *= osg::Matrix::rotate(osg::DegreesToRadians(-1.0), 1, 0, 0);
                pTrans->setMatrix(matrix);
                flag = true;
                break;
            case osgGA::GUIEventAdapter::KEY_Down:      // 下方向键-向下旋转1度
            case osgGA::GUIEventAdapter::KEY_S:         // S键-向下旋转1度
                matrix *= osg::Matrix::rotate(osg::DegreesToRadians(1.0), 1, 0, 0);
                pTrans->setMatrix(matrix);
                flag = true;
                break;
            default:
                break;
        }
        break;
    case osgGA::GUIEventAdapter::EventType::SCROLL:
        switch (guiEventAdapter.getScrollingMotion())
        {
            case osgGA::GUIEventAdapter::SCROLL_UP:     // 鼠标滚轮向上放大
                _scale *= 1.03;
                matrix = matrix * matrix.scale(_scale/matrix.getScale().x(),
                                               _scale/matrix.getScale().x(),
                                               _scale/matrix.getScale().x());
                pTrans->setMatrix(matrix);
                flag = true;
                break;
            case osgGA::GUIEventAdapter::SCROLL_DOWN:   // 鼠标滚轮向下缩小
                _scale *= 0.93;
                matrix = matrix * matrix.scale(_scale/matrix.getScale().x(),
                                               _scale/matrix.getScale().x(),
                                               _scale/matrix.getScale().x());
                pTrans->setMatrix(matrix);
                flag = true;
                break;
            default:
                break;
        }
        break;
    case osgGA::GUIEventAdapter::EventType::PUSH:
        switch (guiEventAdapter.getButton()) {
        case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:     // 鼠标左键:显示
            pSwitch->setNodeMask(1);
            break;
        case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:    // 鼠标右键:隐藏
            pSwitch->setNodeMask(0);
            break;
        case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:   // 鼠标中间:重置
            pSwitch->setNodeMask(1);
            _scale = 1.0;
            matrix = matrix * matrix.scale(_scale/matrix.getScale().x(),
                                           _scale/matrix.getScale().x(),
                                           _scale/matrix.getScale().x());
            matrix = matrix.rotate(osg::DegreesToRadians(0.0), 1, 1, 1);
            pTrans->setMatrix(matrix);
            break;
        default:
            break;
        }
        break;
    default:
        break;
    }
    // 返回false会继续向下个事件处理类传递
//    return flag;
    // 返回true则消息被截取,不会向下个事件处理类传递
    return true;
}

 

操作过程

        恢复原始状态

        OSG开发笔记(十四):OSG交互_第3张图片

        方向键、WASD移动

        OSG开发笔记(十四):OSG交互_第4张图片

        放大(注意:变暗了)

        OSG开发笔记(十四):OSG交互_第5张图片

        隐藏

        OSG开发笔记(十四):OSG交互_第6张图片

        恢复原始状态

        OSG开发笔记(十四):OSG交互_第7张图片

 

工程模板:对应版本号1.11.0

        对应版本号1.11.0


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

你可能感兴趣的:(Qt开发专栏,OSG,OSG三维开发专栏)