ogre3D学习基础10 -- 键盘控制与鼠标控制(直接控制)
要實現鍵盤,鼠標對場景的控制,首先要幀監聽,就是在每一幀的渲染前后對它進行操作。這里的操作沒有用到緩沖區,只是簡單的直接獲取。
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 -- 键盘控制与鼠标控制(直接控制)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Qt界面设计1
- 下一篇: 一步一步深入spring(6)--使用基