若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/96422466
目录
前言
交互概述
交互实现方式与步骤
交互动作
模型多种类型动作的理解
代码
地球代码
事件代码
操作过程
工程模板:对应版本号1.11.0
《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模型固定路径动画》
持续补充中…
交互一般指鼠标和键盘、也可以是触摸等,在地球的基础上增加方向键控制旋转、鼠标控制显示、缩放和重置模型状态。
操作三维场景主要是操作三维场景数据,场景数据主要由viewer负责进行渲染,要得到数据可以使用viewer->getSceneData()就可以了。
Viewer主要功能是控制场景,是场景的核心类。
Viewer中有addEventHandler就是专门添加时间处理器相应交互动作的(鼠标和键盘),可以自己写事件处理器,对事件进行处理。
事件类型有很多,一个viewer可以相应ABCD等等多个事件,一个事件也可以拦截事件,也就是A处理完后给BCD处理,也可以拦截住使BCD收不到事件。
存在事件,必然存在事件参数,给事件A传递参数,不必非要使用viewer进行处理,可以把viewer当参数传递进去。
本次介绍的方式是非回调方式,继承GUI事件类并重写虚函数即可。
交互的实现方式是继承GUI事件类,然后重写其虚函数,步骤如下:
此处有三个虚函数,视作A1、A2、A3三个虚函数
我们只需重载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;
}
恢复原始状态
方向键、WASD移动
放大(注意:变暗了)
隐藏
恢复原始状态
对应版本号1.11.0
原博主博客地址:https://blog.csdn.net/qq21497936
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/96422466