ogre3D学习基础10 -- 键盘控制与鼠标控制(直接控制)
要實現(xiàn)鍵盤,鼠標(biāo)對場景的控制,首先要幀監(jiān)聽,就是在每一幀的渲染前后對它進(jìn)行操作。這里的操作沒有用到緩沖區(qū),只是簡單的直接獲取。
1、這些步驟和前面的一樣,直接上代碼,操作還是在createScene函數(shù)里。代碼如下:
1 void createScene() 2 { 3 //載入實體 4 mSceneMgr->setAmbientLight(ColourValue(0.25,0.25,0.25));//設(shè)置環(huán)境色 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 //第一個攝像機(jī)節(jié)點 17 node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode1",Vector3(-400,200,400)); 18 node1->yaw(Degree(-45));//繞y軸順時針旋轉(zhuǎn)45度 19 node1->attachObject(mCamera); 20 //第二個攝像機(jī)節(jié)點 21 node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode2",Vector3(0,200,400)); 22 }這些代碼就不解釋了,如果不懂,請往前看。
2、綁定攝像機(jī)到節(jié)點
1 void createCamera() 2 { 3 //其他參數(shù)選擇默認(rèn) 4 mCamera = mSceneMgr->createCamera("PlayerCam"); 5 mCamera->setNearClipDistance(5); 6 }3、新建一個類ExampleTestFrameListener,父類為ExampleFrameListener,對鼠標(biāo)和鍵盤的控制主要在這里面進(jìn)行。其中是定義在ExampleApplication.h中的一個類,負(fù)責(zé)幀監(jiān)聽。構(gòu)造函數(shù)如下:ExampleTestFrameListener(RenderWindow *win,Camera *cam,SceneManager *sceneMgr);
現(xiàn)在開始逐漸對他進(jìn)行完善:
首先添加成員變量:
1 bool mMouseDown; // 鼠標(biāo)左鍵是否在上一幀被按下 2 Real mToggle; // 直到下一次觸發(fā)的時間 3 Real mRotate; // 滾動常量 4 Real mMove; // 移動常量 5 SceneManager *mSceneMgr; // 當(dāng)前場景管理器 6 SceneNode *mCamNode; // 當(dāng)前攝像機(jī)所附在的場景節(jié)點在構(gòu)造函數(shù)里對他們進(jìn)行初始化:
1 ExampleTestFrameListener(RenderWindow *win,Camera *cam,SceneManager *sceneMgr) 2 :ExampleFrameListener(win,cam,false,false)//第三個參數(shù)指明是否使用帶緩沖的鍵盤輸入,第四個參數(shù)指明是否使用帶緩沖的鼠標(biāo)輸入 3 { 4 mMouseDown = false;//鍵盤狀態(tài)記錄 5 mToggle = 0;//鼠標(biāo)狀態(tài)記錄 6 mCamNode = cam->getParentSceneNode();//始終指向父節(jié)點 7 mSceneMgr = sceneMgr; 8 mRotate = 0.13; 9 mMove = 250; 10 }然后我們在每一幀里執(zhí)行動作,方法就是在frameStarted()寫入我們的操作。這個函數(shù)會在每一幀渲染前執(zhí)行。
第一,按下鼠標(biāo)左鍵打開關(guān)閉燈光。
首先獲取鼠標(biāo)的控制權(quán),代碼:mMouse->capture();//俘獲鼠標(biāo)
然后讀取鼠標(biāo)按鍵的當(dāng)前狀態(tài),代碼不難理解。
bool currMouse = mMouse->getMouseState().buttonDown(OIS::MB_Left);//獲取鼠標(biāo)當(dāng)前的狀態(tài)
最后判斷是否更改燈的狀態(tài)
1 if(currMouse && !mMouseDown)2 {3 Light *light = mSceneMgr->getLight("light1");//獲取光源指針4 light->setVisible(!light->isVisible());//根據(jù)上一次的狀態(tài)改變,相當(dāng)于取反,由開到關(guān),由關(guān)到開。5 }6 7 mMouseDown = currMouse;//更新鼠標(biāo)的狀態(tài)關(guān)于鼠標(biāo):
通常 0 是鼠標(biāo)左鍵,1 是右鍵,2 是中鍵。在某些系統(tǒng)里 1 是 中鍵、2 是右鍵。所以我們讀取鼠標(biāo)狀態(tài)沒有使用數(shù)字,而是使用了更加健壯的代碼
mMouse->getMouseState().buttonDown(OIS::MB_Left);這樣能避免由于系統(tǒng)差別造成的問題。
第二步,用鍵盤實現(xiàn)上下左右前后的移動。
首先,也是捕獲鍵盤?mKeyboard->capture();//俘獲鍵盤
其次,實現(xiàn)按下數(shù)字鍵1,2時切換不同的攝像機(jī)
1 mToggle -= evt.timeSinceLastFrame;//減去從上一幀到現(xiàn)在所經(jīng)歷的時間,保證正在渲染時不切換攝像機(jī) 2 if ((mToggle <0.0f) && mKeyboard->isKeyDown(OIS::KC_1))//按下數(shù)字鍵1時選擇攝像機(jī)1 3 { 4 mToggle = 0.5f;// 5 mCamera->getParentSceneNode()->detachObject(mCamera);//將當(dāng)前攝像機(jī)從場景節(jié)點上卸載下來6 mCamNode = mSceneMgr->getSceneNode("CamNode1");//獲取攝像機(jī)1的指針 7 mCamNode->attachObject(mCamera);//重新綁定新的攝像機(jī) 8 }9 else if ((mToggle <0.0f) && mKeyboard->isKeyDown(OIS::KC_2))//按下數(shù)字鍵1時選擇攝像機(jī)110 {11 mToggle = 0.5f;//12 mCamera->getParentSceneNode()->detachObject(mCamera);//將當(dāng)前攝像機(jī)從場景節(jié)點上卸載下來13 mCamNode = mSceneMgr->getSceneNode("CamNode2");//獲取攝像機(jī)2的指針14 mCamNode->attachObject(mCamera);//重新綁定新的攝像機(jī)15 }
其中的變量mToggle很關(guān)鍵,可以保證每一幀的渲染操作都是原子操作,不被中途打斷,避免產(chǎn)生不可預(yù)測問題。?
再次,實現(xiàn)按鍵W,A,S,D的平移,這里需要一個三元組transVector3用來保存當(dāng)前攝像機(jī)的位置。
實現(xiàn)前后的移動,其實就是讓坐標(biāo)z增大或者減小,代碼如下
1 Vector3 transVector = Vector3::ZERO;//保存平移方位2 if (mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W))//前3 {4 transVector.z -= mMove;//z軸負(fù)方向移動5 }6 if (mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S))//后7 {8 transVector.z += mMove;//z軸正方向移動9 }其他的移動操作,基本一樣,只需改變z為x或y。具體代碼在最后面。
OIS:
開放輸入系統(tǒng)(OIS)提供了三個主要的類來獲得輸入:Keyboard, Mouse, 和Joystick(搖桿) 。
第三,實現(xiàn)按下鼠標(biāo)右鍵時以一定傾斜角度拖動攝像機(jī)
按下鼠標(biāo)右鍵時拖動,攝像機(jī)以一定的傾斜角度改變
//根據(jù)從上一幀開始鼠標(biāo)移動的距離來控制攝像機(jī)的俯仰偏斜。if (mMouse->getMouseState().buttonDown(OIS::MB_Right)){mCamNode->yaw(Degree(-mRotate * mMouse->getMouseState().X.rel),Node::TS_WORLD);//以y為基礎(chǔ)旋轉(zhuǎn) mCamNode->pitch(Degree(-mRotate * mMouse->getMouseState().Y.rel),Node::TS_LOCAL);//以x為基礎(chǔ)旋轉(zhuǎn) }第四,在ExampleTestApplication中注冊幀監(jiān)聽器
具體操作時在createFrameListener()函數(shù)中,添加以下幾行代碼
1 mFrameListener = new ExampleTestFrameListener(mWindow,mCamera,mSceneMgr);//創(chuàng)建一個幀監(jiān)聽器2 mRoot->addFrameListener(mFrameListener);//注冊到Root類中3 mFrameListener->showDebugOverlay(true);//在層上顯示幀狀態(tài)好了,完整代碼:
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)//第三個參數(shù)指明是否使用 9 //帶緩沖的鍵盤輸入,第四個參數(shù)指明是否使用帶緩沖的鼠標(biāo)輸入( 10 { 11 mMouseDown = false;// 鍵盤和鼠標(biāo)狀態(tài)追蹤 12 mToggle = 0; 13 14 mCamNode = cam->getParentSceneNode(); 15 mSceneMgr = sceneMgr; 16 //設(shè)置旋轉(zhuǎn)和移動速度 17 mRotate = 0.13; 18 mMove = 250; 19 } 20 bool frameStarted(const FrameEvent& evt) 21 { 22 mMouse->capture();//俘獲鼠標(biāo) 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);//獲取鼠標(biāo)當(dāng)前的狀態(tài) 31 if(currMouse && !mMouseDown) 32 { 33 Light *light = mSceneMgr->getLight("light1");//獲取燈光指針 34 light->setVisible(!light->isVisible());//根據(jù)上一次的狀態(tài)改變 35 } 36 37 mMouseDown = currMouse;//更新鼠標(biāo)狀態(tài) 38 39 mToggle -= evt.timeSinceLastFrame;//減去從上一幀到現(xiàn)在所經(jīng)歷的時間,保證正在渲染時不切換攝像機(jī) 40 if ((mToggle <0.0f) && mKeyboard->isKeyDown(OIS::KC_1))//按下數(shù)字鍵1時選擇攝像機(jī)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))//按下數(shù)字鍵1時選擇攝像機(jī)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軸負(fù)方向移動 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軸負(fù)方向移動 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軸負(fù)方向移動 75 } 76 if (mKeyboard->isKeyDown(OIS::KC_PGDOWN) || mKeyboard->isKeyDown(OIS::KC_E))//下 77 { 78 transVector.y += mMove;//Y軸正方向移動 79 } 80 81 //根據(jù)從上一幀開始鼠標(biāo)移動的距離來控制攝像機(jī)的俯仰偏斜。 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;// 鼠標(biāo)左鍵是否在上一幀被按下 96 Real mToggle;//直到下一次觸發(fā)的時間間隔 97 Real mRotate;//滾動常量 98 Real mMove;//移動常量 99 SceneManager *mSceneMgr;//當(dāng)前的場景管理器 100 SceneNode *mCamNode;//當(dāng)前的攝像機(jī)所綁定的場景節(jié)點 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 //其他參數(shù)選擇默認(rèn) 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));//設(shè)置環(huán)境色 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 //第一個攝像機(jī)節(jié)點 140 node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode1",Vector3(-400,200,400)); 141 node1->yaw(Degree(-45));//繞y軸順時針旋轉(zhuǎn)45度 142 node1->attachObject(mCamera); 143 //第二個攝像機(jī)節(jié)點 144 node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode2",Vector3(0,200,400)); 145 } 146 void createFrameListener() 147 { 148 mFrameListener = new ExampleTestFrameListener(mWindow,mCamera,mSceneMgr);//創(chuàng)建一個幀監(jiān)聽器 149 mRoot->addFrameListener(mFrameListener);//注冊到Root類中 150 mFrameListener->showDebugOverlay(true);//在層上顯示幀狀態(tài) 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格式的動畫上來的,可一直沒找到好工具。
轉(zhuǎn)載于:https://www.cnblogs.com/songliquan/p/3302228.html
總結(jié)
以上是生活随笔為你收集整理的ogre3D学习基础10 -- 键盘控制与鼠标控制(直接控制)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Qt界面设计1
- 下一篇: happens-before规则和指令重