要实现键盘,鼠标对场景的控制,首先要帧监听,就是在每一帧的渲染前后对它进行操作。这里的操作没有用到缓冲区,只是简单的直接获取。

  1、这些步骤和前面的一样,直接上代码,操作还是在createScene函数里。代码如下:

 1     void createScene()
 2     {
 3         //载入实体
 4         mSceneMgr->setAmbientLight(ColourValue(0.25,0.25,0.25));//设置环境色
 5         Entity *ent1 = mSceneMgr->createEntity("ninja","ninja.mesh");
 6         SceneNode *node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("ninjaNode");
 7         node1->attachObject(ent1);
 8
 9         //点光源
10         Light *light = mSceneMgr->createLight("light1");
11         light->setType(Light::LT_POINT);//点光源
12         light->setPosition(Vector3(250,150,250));
13         light->setDiffuseColour(ColourValue::White);//漫射光
14         light->setSpecularColour(ColourValue::White);//反射光
15
16         //第一个摄像机节点
17         node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode1",Vector3(-400,200,400));
18         node1->yaw(Degree(-45));//绕y轴顺时针旋转45度
19         node1->attachObject(mCamera);
20         //第二个摄像机节点
21         node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode2",Vector3(0,200,400));
22     }

  这些代码就不解释了,如果不懂,请往前看。

  2、绑定摄像机到节点

1 void createCamera()
2     {
3         //其他参数选择默认
4         mCamera = mSceneMgr->createCamera("PlayerCam");
5         mCamera->setNearClipDistance(5);
6     }

  3、新建一个类ExampleTestFrameListener,父类为ExampleFrameListener,对鼠标和键盘的控制主要在这里面进行。其中是定义在ExampleApplication.h中的一个类,负责帧监听。构造函数如下:ExampleTestFrameListener(RenderWindow *win,Camera *cam,SceneManager *sceneMgr);

  现在开始逐渐对他进行完善:

  首先添加成员变量

1 bool mMouseDown; // 鼠标左键是否在上一帧被按下
2 Real mToggle; // 直到下一次触发的时间
3 Real mRotate; // 滚动常量
4 Real mMove; // 移动常量
5 SceneManager *mSceneMgr; // 当前场景管理器
6 SceneNode *mCamNode; // 当前摄像机所附在的场景节点

  在构造函数里对他们进行初始化

 1 ExampleTestFrameListener(RenderWindow *win,Camera *cam,SceneManager *sceneMgr)
 2         :ExampleFrameListener(win,cam,false,false)//第三个参数指明是否使用带缓冲的键盘输入,第四个参数指明是否使用带缓冲的鼠标输入
 3     {
 4         mMouseDown = false;//键盘状态记录
 5         mToggle = 0;//鼠标状态记录
 6         mCamNode = cam->getParentSceneNode();//始终指向父节点
 7         mSceneMgr = sceneMgr;
 8         mRotate = 0.13;
 9         mMove = 250;
10     }

  然后我们在每一帧里执行动作,方法就是在frameStarted()写入我们的操作。这个函数会在每一帧渲染前执行。

  第一,按下鼠标左键打开关闭灯光。

    首先获取鼠标的控制权,代码:mMouse->capture();//俘获鼠标

    然后读取鼠标按键的当前状态,代码不难理解。

      bool currMouse = mMouse->getMouseState().buttonDown(OIS::MB_Left);//获取鼠标当前的状态

    最后判断是否更改灯的状态

    1 if(currMouse && !mMouseDown)2         {3             Light *light = mSceneMgr->getLight("light1");//获取光源指针4             light->setVisible(!light->isVisible());//根据上一次的状态改变,相当于取反,由开到关,由关到开。5         }6 7         mMouseDown = currMouse;//更新鼠标的状态

    关于鼠标:

    通常 0 是鼠标左键,1 是右键,2 是中键。在某些系统里 1 是 中键、2 是右键。所以我们读取鼠标状态没有使用数字,而是使用了更加健壮的代码

    mMouse->getMouseState().buttonDown(OIS::MB_Left);这样能避免由于系统差别造成的问题。

  第二步,用键盘实现上下左右前后的移动。

    首先,也是捕获键盘 mKeyboard->capture();//俘获键盘

    其次,实现按下数字键1,2时切换不同的摄像机

   1      mToggle -= evt.timeSinceLastFrame;//减去从上一帧到现在所经历的时间,保证正在渲染时不切换摄像机 2         if ((mToggle <0.0f) && mKeyboard->isKeyDown(OIS::KC_1))//按下数字键1时选择摄像机1 3         { 4             mToggle = 0.5f;// 5             mCamera->getParentSceneNode()->detachObject(mCamera);//将当前摄像机从场景节点上卸载下来   6             mCamNode = mSceneMgr->getSceneNode("CamNode1");//获取摄像机1的指针 7             mCamNode->attachObject(mCamera);//重新绑定新的摄像机 8         }9         else if ((mToggle <0.0f) && mKeyboard->isKeyDown(OIS::KC_2))//按下数字键1时选择摄像机110         {11             mToggle = 0.5f;//12             mCamera->getParentSceneNode()->detachObject(mCamera);//将当前摄像机从场景节点上卸载下来13             mCamNode = mSceneMgr->getSceneNode("CamNode2");//获取摄像机2的指针14             mCamNode->attachObject(mCamera);//重新绑定新的摄像机15         }

    其中的变量mToggle很关键,可以保证每一帧的渲染操作都是原子操作,不被中途打断,避免产生不可预测问题。

    再次,实现按键W,A,S,D的平移,这里需要一个三元组transVector3用来保存当前摄像机的位置。

      实现前后的移动,其实就是让坐标z增大或者减小,代码如下

  1      Vector3 transVector = Vector3::ZERO;//保存平移方位2         if (mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W))//前3         {4             transVector.z -= mMove;//z轴负方向移动5         }6         if (mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S))//后7         {8             transVector.z += mMove;//z轴正方向移动9         }

      其他的移动操作,基本一样,只需改变z为x或y。具体代码在最后面。

    OIS:  

    开放输入系统(OIS)提供了三个主要的类来获得输入:Keyboard, Mouse, 和Joystick(摇杆) 。

  第三,实现按下鼠标右键时以一定倾斜角度拖动摄像机

    按下鼠标右键时拖动,摄像机以一定的倾斜角度改变

       //根据从上一帧开始鼠标移动的距离来控制摄像机的俯仰偏斜。if (mMouse->getMouseState().buttonDown(OIS::MB_Right)){mCamNode->yaw(Degree(-mRotate * mMouse->getMouseState().X.rel),Node::TS_WORLD);//以y为基础旋转
            mCamNode->pitch(Degree(-mRotate * mMouse->getMouseState().Y.rel),Node::TS_LOCAL);//以x为基础旋转
        }

  第四,在ExampleTestApplication中注册帧监听器

    具体操作时在createFrameListener()函数中,添加以下几行代码

  1      mFrameListener = new ExampleTestFrameListener(mWindow,mCamera,mSceneMgr);//创建一个帧监听器2         mRoot->addFrameListener(mFrameListener);//注册到Root类中3         mFrameListener->showDebugOverlay(true);//在层上显示帧状态

  好了,完整代码:

  

  1 #include "ExampleApplication.h"
  2 using namespace Ogre;
  3
  4 class ExampleTestFrameListener:public ExampleFrameListener
  5 {
  6 public:
  7     ExampleTestFrameListener(RenderWindow *win,Camera *cam,SceneManager *sceneMgr)
  8         :ExampleFrameListener(win,cam,false,false)//第三个参数指明是否使用
  9         //带缓冲的键盘输入,第四个参数指明是否使用带缓冲的鼠标输入(
 10     {
 11         mMouseDown = false;// 键盘和鼠标状态追踪
 12         mToggle = 0;
 13
 14         mCamNode = cam->getParentSceneNode();
 15         mSceneMgr = sceneMgr;
 16         //设置旋转和移动速度
 17         mRotate = 0.13;
 18         mMove = 250;
 19     }
 20     bool frameStarted(const FrameEvent& evt)
 21     {
 22         mMouse->capture();//俘获鼠标
 23         mKeyboard->capture();//俘获键盘
 24
 25         if (mKeyboard->isKeyDown(OIS::KC_ESCAPE))//按下esc键
 26         {
 27             return false;
 28         }
 29
 30         bool currMouse = mMouse->getMouseState().buttonDown(OIS::MB_Left);//获取鼠标当前的状态
 31         if(currMouse && !mMouseDown)
 32         {
 33             Light *light = mSceneMgr->getLight("light1");//获取灯光指针
 34             light->setVisible(!light->isVisible());//根据上一次的状态改变
 35         }
 36
 37         mMouseDown = currMouse;//更新鼠标状态
 38
 39         mToggle -= evt.timeSinceLastFrame;//减去从上一帧到现在所经历的时间,保证正在渲染时不切换摄像机
 40         if ((mToggle <0.0f) && mKeyboard->isKeyDown(OIS::KC_1))//按下数字键1时选择摄像机1
 41         {
 42             mToggle = 0.5f;
 43             mCamera->getParentSceneNode()->detachObject(mCamera);
 44             mCamNode = mSceneMgr->getSceneNode("CamNode1");
 45             mCamNode->attachObject(mCamera);
 46         }
 47         else if ((mToggle <0.0f) && mKeyboard->isKeyDown(OIS::KC_2))//按下数字键1时选择摄像机1
 48         {
 49             mToggle = 0.5f;
 50             mCamera->getParentSceneNode()->detachObject(mCamera);
 51             mCamNode = mSceneMgr->getSceneNode("CamNode2");
 52             mCamNode->attachObject(mCamera);
 53         }
 54
 55         Vector3 transVector = Vector3::ZERO;//保存平移方位
 56         if (mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W))//前
 57         {
 58             transVector.z -= mMove;//z轴负方向移动
 59         }
 60         if (mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S))//后
 61         {
 62             transVector.z += mMove;//z轴正方向移动
 63         }
 64         if (mKeyboard->isKeyDown(OIS::KC_LEFT) || mKeyboard->isKeyDown(OIS::KC_A))//左
 65         {
 66             transVector.x -= mMove;//x轴负方向移动
 67         }
 68         if (mKeyboard->isKeyDown(OIS::KC_RIGHT) || mKeyboard->isKeyDown(OIS::KC_D))//右
 69         {
 70             transVector.x += mMove;//x轴正方向移动
 71         }
 72         if (mKeyboard->isKeyDown(OIS::KC_PGUP) || mKeyboard->isKeyDown(OIS::KC_Q))//上
 73         {
 74             transVector.y -= mMove;//Y轴负方向移动
 75         }
 76         if (mKeyboard->isKeyDown(OIS::KC_PGDOWN) || mKeyboard->isKeyDown(OIS::KC_E))//下
 77         {
 78             transVector.y += mMove;//Y轴正方向移动
 79         }
 80
 81         //根据从上一帧开始鼠标移动的距离来控制摄像机的俯仰偏斜。
 82         if (mMouse->getMouseState().buttonDown(OIS::MB_Right))
 83         {
 84             mCamNode->yaw(Degree(-mRotate * mMouse->getMouseState().X.rel),Node::TS_WORLD);
 85             mCamNode->pitch(Degree(-mRotate * mMouse->getMouseState().Y.rel),Node::TS_LOCAL);
 86         }
 87         return true;
 88         //return ExampleFrameListener::frameStarted(evt);
 89     }
 90     bool frameEnded(const FrameEvent& evt)
 91     {
 92         return ExampleFrameListener::frameEnded(evt);
 93     }
 94 protected:
 95     bool mMouseDown;// 鼠标左键是否在上一帧被按下
 96     Real mToggle;//直到下一次触发的时间间隔
 97     Real mRotate;//滚动常量
 98     Real mMove;//移动常量
 99     SceneManager *mSceneMgr;//当前的场景管理器
100     SceneNode *mCamNode;//当前的摄像机所绑定的场景节点
101 private:
102 };
103
104
105 class ExampleTestApplication:public ExampleApplication
106 {
107 public:
108     ExampleTestApplication()
109     {
110
111     }
112     ~ExampleTestApplication()
113     {
114
115     }
116
117 protected:
118     void createCamera()
119     {
120         //其他参数选择默认
121         mCamera = mSceneMgr->createCamera("PlayerCam");
122         mCamera->setNearClipDistance(5);
123     }
124     void createScene()
125     {
126         //载入实体
127         mSceneMgr->setAmbientLight(ColourValue(0.25,0.25,0.25));//设置环境色
128         Entity *ent1 = mSceneMgr->createEntity("ninja","ninja.mesh");
129         SceneNode *node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("ninjaNode");
130         node1->attachObject(ent1);
131
132         //点光源
133         Light *light = mSceneMgr->createLight("light1");
134         light->setType(Light::LT_POINT);//点光源
135         light->setPosition(Vector3(250,150,250));
136         light->setDiffuseColour(ColourValue::White);//漫射光
137         light->setSpecularColour(ColourValue::White);//反射光
138
139         //第一个摄像机节点
140         node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode1",Vector3(-400,200,400));
141         node1->yaw(Degree(-45));//绕y轴顺时针旋转45度
142         node1->attachObject(mCamera);
143         //第二个摄像机节点
144         node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode2",Vector3(0,200,400));
145     }
146     void createFrameListener()
147     {
148         mFrameListener = new ExampleTestFrameListener(mWindow,mCamera,mSceneMgr);//创建一个帧监听器
149         mRoot->addFrameListener(mFrameListener);//注册到Root类中
150         mFrameListener->showDebugOverlay(true);//在层上显示帧状态
151     }
152 };
153
154 #include "windows.h"
155
156
157
158 INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
159
160
161 {
162     ExampleTestApplication app;
163         app.go();
164     return 0;
165 }

全部代码

  图片就不上了,本来想截取几个gif格式的动画上来的,可一直没找到好工具。

转载于:https://www.cnblogs.com/songliquan/p/3302228.html

ogre3D学习基础10 -- 键盘控制与鼠标控制(直接控制)相关推荐

  1. 【Win32 API学习】模拟键盘输入和鼠标输入

    在Windows大行其道的今天,windows界面程序受到广大用户的欢迎.对这些程序的操作不外乎两种,键盘输入控制和鼠标输入控制.有时,对于繁杂的,或重复性的输入操作,我们能否通过编制程序来代替手工输 ...

  2. ogre3D学习基础14 -- 雾化效果与天空面,天空盒,天空穹

    前几天设置天空盒时一直出问题,现在问题终于解决了,问题来的莫名其妙,走的也莫名其妙. 第一,还是框架,我们依然使用ExampleApplication文件,框架如下 1 #include " ...

  3. ogre3D学习基础4 -- 网格工具与硬件缓存

    三.网格工具(Mesh) 1.导出器(Exporters)--- 用于从模型生成器中得到数据并且导入到OGRE中去. 导出器是指通过3D模型工具的插件写成网格数据和骨骼动画的文件格式可以在OGRE中被 ...

  4. 史上最牛最强的linux学习笔记 10.shell基础

    史上最牛最强的linux学习笔记 10.shell基础 写在最前面: 本文是基于某站的视频学习所得,第一个链接如下: https://www.bilibili.com/video/BV1mW411i7 ...

  5. 【OpenGL学习笔记⑧】——键盘控制正方体+光源【冯氏光照模型 光照原理 环境光照+漫反射光照+镜面光照】

    ✅ 重点参考了 LearnOpenGL CN 的内容,但大部分知识内容,小编已作改写,以方便读者理解. 文章目录 零. 成果预览图 一. 光照原理与投光物的配置 1.1 光照原理 1.2 投光物 二. ...

  6. Python|http|Chrome Developer Tools|Postman|HTTPie|builtwith库|python-whois库|爬虫及解析|语言基础50课:学习(10)

    文章目录 系列目录 原项目地址 第31课:网络数据采集概述 爬虫的应用领域 爬虫合法性探讨 Robots协议 超文本传输协议(HTTP) 相关工具(Chrome Developer Tools.Pos ...

  7. WPF and Silverlight 学习笔记(十四):键盘输入、鼠标输入、焦点处理[转]

    一.键盘类和键盘事件 WPF提供了基础的键盘类(System.Input.Keyboard类),该类提供与键盘相关的事件.方法和属性,这些事件.方法和属性提供有关键盘状态的信息.Keyboard的事件 ...

  8. mfc键盘控制移动鼠标光标_如何在Windows中使用键盘控制鼠标光标

    mfc键盘控制移动鼠标光标 If you're stuck without a mouse temporarily, don't worry-you can still use your PC. Yo ...

  9. 深度学习(10)TensorFlow基础操作六: 数学运算

    深度学习(10)TensorFlow基础操作六: 数学运算 1. Operation type 2. + - * / % // 3. tf.math.log & tf.exp 4. log2, ...

最新文章

  1. java并发框架支持锁包括,tip/面试题_并发与多线程.md at master · 171437912/tip · GitHub...
  2. jquery 配合 ajax 完成 在线编辑 你值得拥有
  3. wpf cefsharp html源码,CefSharp For WPF基本使用
  4. 选择互斥 html,利用JS对两行Input radio 进行互斥选择。
  5. python echarts mysql python_Django中从mysql数据库中获取数据传到echarts方式
  6. # 保持最外层获取焦点_大事件!沈阳爱尔白内障焕晶诊疗中心正式启用,两位PanOptix三焦点人工晶体植入患者清晰见证!...
  7. 怎么解决交换机端口不正常问题?
  8. 【kafka】kafka 指定分区消费 不会触发 reblance
  9. 13 大论坛同开播!数百专家带你从机器学习技术与工程实践,聊到开源生态 | AI ProCon 2020...
  10. 安卓10侧边返回_Flyme 8 体验:可能是最好的国产安卓系统
  11. centos 安装mysql-proxy_详解在Centos 5.2下安装最新Mysql Proxy LUA教程
  12. 如何将自己在github写的android library开源,让大家依赖使用
  13. MySQL 5之存储过程
  14. matlab中TCR触发,TCR+FC型SVC的研究及MATLAB仿真
  15. ISO27145协议解析
  16. MATLAB2017b libsvm安装教程
  17. 光纤跳线接口_如何为10G SFP+光模块搭配对应的光纤跳线类型?
  18. 如何发表SCI论文?写SCI文章的心得
  19. 通过自定义的key进行加密解密
  20. 高通平台开发系列讲解(AtCoP篇)AtCoP架构简介

热门文章

  1. 史上最易懂的 Kubernetes 儿童插图指南
  2. 为什么很多公司转型Go语言开发?Go语言能做什么
  3. MySQL 如何查找删除重复行?
  4. 一文盘点数据行业的动态演变
  5. 致传统企业朋友:不够痛就别微服务,有坑
  6. 拿什么来衡量程序员的生产力?
  7. 轮播图js怎么设置图片自适应大小
  8. 职责链模式 php,php Chain of Responsibility 职责链模式
  9. oracle executesqlcommand,Oracle Execute Command Sql Script in Win
  10. 云计算灾备:灾备通识