当前位置: 首页 > news >正文

【OSG学习笔记】Day 13: 事件处理——响应键盘与鼠标

在这里插入图片描述

OpenSceneGraph (OSG) 中,事件处理是实现用户交互功能的重要部分。

通过自定义按键事件(如 WASD 键控制模型移动),可以让用户与场景进行互动。

osgGA::GUIEventHandler

osgGA::GUIEventHandlerOpenSceneGraph (OSG) 中用于处理用户输入事件(如键盘、鼠标等)的一个基类。

通过继承 osgGA::GUIEventHandler 并重写其方法,可以实现自定义的事件处理逻辑,以便对用户的交互做出响应。

创建自定义事件处理器

OSG 提供了一个基类 osgGA::GUIEventHandler,可以用来自定义事件处理逻辑。

我们需要继承这个类,并重写其 handle() 方法。

#include <osgViewer/Viewer>
#include <osg/MatrixTransform>
#include <osgGA/GUIEventHandler>
#include <osg/PositionAttitudeTransform>// 自定义事件处理器
class CustomKeyboardHandler : public osgGA::GUIEventHandler {
public:CustomKeyboardHandler(osg::ref_ptr<osg::PositionAttitudeTransform> transform): _transform(transform), _moveSpeed(1.0f) {}// 重写 handle() 方法bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter&) override {switch (ea.getEventType()) {case osgGA::GUIEventAdapter::KEYDOWN: {float delta = _moveSpeed; // 移动速度osg::Vec3d pos = _transform->getPosition(); // 获取当前模型位置switch (ea.getKey()) {case 'w': case 'W': // 向前移动pos.z() += delta;break;case 's': case 'S': // 向后移动pos.z() -= delta;break;case 'a': case 'A': // 向左移动pos.x() -= delta;break;case 'd': case 'D': // 向右移动pos.x() += delta;break;default:return false; // 未处理的按键}_transform->setPosition(pos); // 更新模型位置return true; // 表示事件已处理}default:return false; // 其他事件未处理}}private:osg::ref_ptr<osg::PositionAttitudeTransform> _transform; // 模型变换节点float _moveSpeed; // 移动速度
};

设置场景中的可移动模型

为了演示 WASD 控制,我们需要一个模型,并将其附加到 osg::PositionAttitudeTransform 节点上。

这个节点允许我们轻松地调整模型的位置和姿态。

osg::ref_ptr<osg::Node> createModel() {// 创建一个简单的几何体作为模型(例如立方体)osg::ref_ptr<osg::Geode> geode = new osg::Geode;geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0, 0, 0), 1.0f)));return geode.release();
}

整合事件处理器

将自定义事件处理器添加到 OSG 的视图器中,并运行程序。

int main() {// 创建视图器osgViewer::Viewer viewer;// 创建一个 PositionAttitudeTransform 节点用于控制模型位置osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;transform->addChild(createModel()); // 将模型添加到变换节点// 将变换节点添加到场景根节点osg::ref_ptr<osg::Group> root = new osg::Group;root->addChild(transform);// 添加自定义事件处理器viewer.addEventHandler(new CustomKeyboardHandler(transform));// 设置场景数据viewer.setSceneData(root);// 运行视图器return viewer.run();
}

实战

我们来实现让我们的钢铁侠动起来的效果。

代码如下:

#include <osg/Geode>
#include <osg/ShapeDrawable>
#include <osg/MatrixTransform>
#include <osgViewer/Viewer>
#include <osgGA/GUIEventHandler>
#include <osgDB/ReadFile>
#include <iostream>
#include <cstdlib>// 自定义事件处理类
class KeyHandler : public osgGA::GUIEventHandler
{
public:KeyHandler(osg::MatrixTransform* transform) : _transform(transform) {}virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa){switch (ea.getEventType()){case osgGA::GUIEventAdapter::KEYDOWN:switch (ea.getKey()){case 'w':case 'W':// 向前移动translateNode(osg::Vec3(0.0f, 10.0f, 0.0f));return true;case 'a':case 'A':// 向左移动translateNode(osg::Vec3(-10.0f, 0.0f, 0.0f));return true;case 's':case 'S':// 向后移动translateNode(osg::Vec3(0.0f, -10.0f, 0.0f));return true;case 'd':case 'D':// 向右移动translateNode(osg::Vec3(10.0f, 0.0f, 0.0f));return true;default:break;}default:break;}return false;}private:void translateNode(const osg::Vec3& translation){// 获取当前矩阵osg::Matrix matrix = _transform->getMatrix();// 对矩阵进行平移操作matrix.preMultTranslate(translation);// 设置新的矩阵_transform->setMatrix(matrix);}osg::ref_ptr<osg::MatrixTransform> _transform;
};int main()
{// 创建Viewer对象osgViewer::Viewer viewer;// 创建一个MatrixTransform节点osg::ref_ptr<osg::MatrixTransform> transform = new osg::MatrixTransform;// 加载模型(支持.osg/.obj格式)osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("../IronMan.osg");  // 替换为你的模型路径// 检查模型是否加载成功if (!model) {std::cerr << "模型加载失败!请检查路径和格式。" << std::endl;return 1;}// 将几何体添加到MatrixTransform节点transform->addChild(model);// 创建场景图的根节点osg::ref_ptr<osg::Group> root = new osg::Group;root->addChild(transform);// 设置场景数据viewer.setSceneData(root);// 创建自定义事件处理程序并添加到Viewerviewer.addEventHandler(new KeyHandler(transform));// 运行Viewerreturn viewer.run();
}

运行效果

在这里插入图片描述
距离做游戏又进了一步。_

在这里插入图片描述

相关文章:

  • 高压直流输电MATLAB/simulink仿真模型+说明文档
  • UDP协议详解+代码演示
  • Nginx支持HTTP2/HTTP3的并用CURL测试
  • 微信小程序连续多个特殊字符自动换行解决方法
  • 在 Ubuntu 24.04 LTS 一台机子上同时部署Dify 1.3.1 和 RAGflow 0.18.0
  • 系统架构-软件可靠性
  • 如何删除此电脑上的迅雷下载、WPS云盘、百度网盘
  • yolov8+kalman 实现目标跟踪统计人流量
  • Spring的BeanFactory和FactoryBean的区别
  • Hibernate-Core (CVE-2020-25638)
  • 线性代数——行列式⭐
  • vue mixin混入与hook
  • vscode以管理员身份运行报错
  • Nacos源码—1.Nacos服务注册发现分析一
  • 蓝桥杯2025年第十六届省赛真题-可分解的正整数
  • Docker镜像仓库技术深度解析
  • 【环境配置】Mac电脑安装运行R语言教程 2025年
  • 半监督学习与强化学习的结合:新兴的智能训练模式
  • 【计算机视觉】Bayer Pattern与Demosaic算法详解:从传感器原始数据到彩色图像
  • 《计算机视觉度量:从特征描述到深度学习》—图片多模态CLIP,BLIP2,DINOv2特征提取综述
  • 澎湃思想周报丨数字时代的育儿;凛冬已至好莱坞
  • “中国游”带火“中国购”,“即买即退”让外国游客购物更丝滑
  • 2025上海浪琴环球马术冠军赛开赛在即,首批赛马今晨抵沪
  • 一季度规模以上工业企业利润由降转增,国家统计局解读
  • 经济日报金观平:充分发挥增量政策的经济牵引力
  • 特朗普说克里米亚将留在俄罗斯,泽连斯基:绝不承认