青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

第三人稱攝象機系統例子

Posted on 2008-07-09 15:42 RichardHe 閱讀(473) 評論(0)  編輯 收藏 引用 所屬分類: OGRE

第三人稱攝象機系統例子

Translator:自由騎士篤志(王宏張)

Data2008-5-14

l        前言

Ogre是一款優秀的3D圖形渲染引擎,在國內,很多前輩從04年甚至更早就對它有了深入的了解,并留了許多譯文和心得,極大的便利了我的學習。雖然我起步比較晚,但仍希望自己學習間的這些記錄和翻譯能夠幫助到他人,如您對Ogre有所心得和資料,望提供至Ogre中文Wiki http://ogre3d.cn/wiki中大家共享交流。

因能力所限,翻譯和整理難免有錯誤之處,歡迎各位指正。

Blog http:\\hi.baidu.com\freedomknightduzhi

E-mail duzhi5368@163.com

大部分譯文來自 http://www.ogre3d.org ,如原文內無說明,不再額外查證來源以及原作者名稱。

 

l        想法來源

這個第三人稱攝象機系統的想法來源于我玩的一款游戲《寂靜嶺2》,在其中有一些圖象上的BUG,我甚至能從其中發現一些不正常的“線”,如果你也看過,你會明白我說的情況。

       一般情況下,該系統中同一時刻內整個場景中有且僅有一個攝象機。和其他的第一/三人稱攝象機系統不同的是,我的這套系統中,攝象機是完全獨立與整個場景的(除根結點Root以外 --- 它是程序的核心)。

       這個系統能使我們獲得非常優秀的特效和軟件環境,也提供了我們一個非常友好的方式來查看整個場景。

       概括來說,這個核心攝象機ExtendedCamera由 兩個場景結點共同組成,它們分別是“攝象機管理器”和“攝象機的對象”。攝象機管理器用來保證攝象機永遠朝向攝象機的對象。如果我們移動“對象”,攝象機 將會平移。如果我們移動“管理器”,則會使攝象機圍繞著“對象”進行旋轉。當然,我們也可以兩者一起移動獲得更多的情況。

       上面是對整個系統的一個簡單功能的說明。我們還可以為攝象機增加一些震動特效,也可以通過虛擬攝象機實現一些電影效果等等。

       下面,我將講述如何在一個Demo中實現三種攝象機模式。

l         可旋轉第三人稱攝象機

首先,我們有一個主角,它有三重性質。首先,它本身是一個重要的場景結點(主角),又是一個可見的結點(我們的攝象機的目標結點),還是一個可旋轉的攝象機結點(主角的眼睛本身可以進行旋轉和觀察)。還有很多方法可以實現同樣的功能,但是我認為這種方法比較簡單。

       我們接下來要做的就是,使它本身“可見的結點”這一特性結點做為我們“攝象機的目標”,而“可旋轉的攝象機結點”這一特性結點做為攝象機本身。

       “可見的結點”意味著主角大部分時間應該處于屏幕的中心,但當主角處于“調查”狀態時,它自身就變成了一個攝象機,這時它能夠獲得更寬闊的視野。

       (譯者:還不理解的朋友可以玩玩單機的《零》系列或射擊類游戲。通常為第三人稱,一旦開啟瞄準鏡時,就變成了第一人稱,即作者所說的“主角成為了一個攝象機結點”。)

l         綁定的第三人稱攝象機

這種類型的攝象機非常常見,例如《寂靜嶺》……(譯者:- -看來作者是SH的粉絲……)這種攝象機意味著攝象機永遠鎖定主角,但僅鎖定一個方面。(譯者:簡單來說即永遠無法旋轉攝象機看到主角的正面。)

這種類型的攝象機與可旋轉的第三人稱攝象機類似。

l         第一人稱攝象機

我們使用主角的位置作為攝象機的位置。在該模式下,我們將攝象機的“目標結點”設置為空,同時也將以主角結點為目標的攝象機隱藏起來。

以上,就是三種攝象機的區別。

l        需要緊記的一些事情

l         調整系統

如果攝象機受到場景中的一些對象影響,我們則需要對攝象機進行一些調整。

l         攝象機移動

攝象機以及攝象機目標點可以這樣移動:我們計算攝象機坐標和目標點之間的差距,最終得到一個矩陣,讓它作用于攝象機使其移動至目標點。

l         緊密器

按照我們上面說的移動方式,我們會感覺到攝象機的移動很生硬,不夠平滑。所以這個“移動緊密器”的概念就出來了。這個緊密器因素是一個0,0 – 1.0之間的值,我們在計算出攝象機的移動轉換矩陣時,用它來進行影響。

       1:若該因素為1.0,則表明當目標單元移動,攝象機同樣移動。

       2:若該因素為0.0,則當目標單元移動時,攝象機完全不動。

       3:該因素在0.0 – 1.0之間時,將會對攝象機的變換矩陣做出影響。

l        源代碼以及說明

你可以從http://www.ugr.es/local/agsh/ogre/ExtendedCameraSample.zip這里下載Alberts的這套代碼。

       首先,我們包含OGRE的例子框架文件頭。

 

       // 攝象機系統例子 By Kencho

       #include “ExampleApplication.h”

 

       接下來,我們定義一個角色類。這個類中將定義一個對象所處的多種特性屬性(即是攝象機又是攝象機的目標對象)。當然,在一個游戲中,你需要為角色類定義更多的屬性。 :)

 

       // 普通角色類

       Class Charater

{

       Protected:

              SceneNode *mMainNode;      // 主角結點

              SceneNode *mSightNode;      // 可見結點,主角應當一直看著這里

              SceneNode *mCameraNode;  // 鎖定攝象機結點,該結點圍繞主角移動和旋轉

              Entity *mEntity;                   // 角色實體

              SceneManager *mSceneMgr;

       Public:

              // 更新主角狀態(如移動等……)

              Virtual void update (Real elapsedTime, InputReader *input) = 0;

              // 下面兩個方法返回攝象機結點指針

              SceneNode *getSightNode(){ return mSightNode ;}

              SceneNode *getCameraNode(){ return mCameraNode; }

              // 返回主角當前坐標(第一人稱攝象機時需要)

              Vector3 getWorldPosition(){ return mMainNode->getWorldPosition(); }

};

 

接下來,我們對角色類特化實現一下。我認為在Demo弄一個漂浮的食人魔腦袋做主角挺不錯。所以我們寫一個實例化的類。

 

       // 特殊的實例化角色類 我們可愛的Ogre

       Class OgreCharater : public Character

{

Protected:

       String mName;

Public:

       OgreCharater(String name, SceneManager *sceneMgr)

{

       // 保存類成員變量

       mName = name;

       mSceneMgr = sceneMgr;

       // 創建節點用來存放綁定第三人稱的攝象機

mMainNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(mName);

    mSightNode = mMainNode-> createChildSceneNode(mName + “_sight”, Vector3(0, 0, 100));

    mCameraNode = mMainNode-> createChildSceneNode(mName + “_camera”, Vector3(0, 50, -100));

    // 為角色綁定一個實體

    mEntity = mSceneMgr->createEntity(mName, “OgreHead.mesh”);

    mMainNode->attachObject(mEntity);

}

 

Void update(Real elapsedTime, InputReader *input)

{

       // 移動

       If (input->isKeyDown(KC_W))

{

       mMainNode->translate(mMainNode->getOrientation() * Vector3(0, 0, 100 * elapsedTime));

}

       If (input->isKeyDown(KC_S))

{

       mMainNode->translate(mMainNode->getOrientation() * Vector3(0, 0, -50 * elapsedTime));

}

       If (input->isKeyDown(KC_A))

{

       mMainNode->yaw(Radian(2 * elapsedTime));;

}

       If (input->isKeyDown(KC_D))

{

       mMainNode->yaw(Radian(-2 * elapsedTime));;

}

}

 

// 設置自身是否可見,這對于第一人稱視角很有用。

Void setVisible(bool visible)

{

       mMainNode->setVisible(visible);

}

};

 

為了保證代碼簡單,我這里不再寫一些關于主角的模型動畫,控制等函數。

       現在,進入有趣的部分:擴展的攝象機類。它就如我之前所說明的思路一樣去設計的,所以,如果你對本部分代碼有什么疑問,你可以看一下先前我的講述。

      

       // 我們的擴展攝象機類

       Class ExtendedCamera

       {

       Protected:

              SceneNode *mTargetNode;    // 攝象機目標結點

              SceneNode *mCameraNode;  // 攝象機自身結點

              Camera *mCamera;              // Ogre攝象機

              SceneManager *mSceneMgr;

              String mName;

              Bool mOwnCamera;             // 判斷是否是本類創建的攝象機,或是類外傳入的攝象機

              Real mTightness;                  // 攝象機捆綁緊密度。1.0表示攝象機與目標的移動保持完全一致。0.0表示攝象機不移動,完全不受目標移動的影響。

       Public:

              ExtendedCamera(String name, SceneManager *sceneMgr, Camera *camera = 0)

{

       mName = name;

       mSceneMgr = sceneMgr;

       // 創建攝象機結點結構

       mCamreaNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(mName);

       mTargetNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(mName + “_target”);

       // 攝象機永遠朝向目標結點

mCameraNode->setAutoTracking(true, mTargetNode);

// 因為需要自動跟蹤,所以該項要設為true

mCameraNode->setFixedYawAxis(true);

 

// 假如沒有從參數獲得一個攝象機,我們則自己創建

If (camera == 0)

{

       mCamera = mSceneMgr->createCamera(mName);

       mOwnCamera = true;

}else

{

       mCamera = camera;

       mOwnCamera = false;

}

// 為攝象機結點綁定一個Ogre攝象機

mCameraNode->attachObject(mCamera);

// 默認的攝象機捆綁緊密系數

mTightness = 0.01f;

}

 

~ExtendedCamera()

{

       mCameraNode->detachAllObjects();

       if (mOwnCamera)

              delete mCamera;

       mSceneMgr->destroySceneNode(mName);

       mSceneMgr-> destroySceneNode(mName + “_target”);

}

 

Void setTightness(Real tightness)

{

       mTightness = tightness;

}

 

Real getTightness()

{

       Return mTightness;

}

 

Vector3 getCameraPosition()

{

       Return mCameraNode->getPosition();

}

 

Void instantUpdate(Vertor3 cameraPosition, Vector3 targetPosition)

{

       mCameraNode->setPosition(cameraPosition);

mTargetNode->setPosition(targetPosition);

}

 

Void update(Real elapsedTime, Vector3 cameraPosition, Vector3 targetPositon)

{

       // 管理移動

       Vector3 displacement;

       Displacement = (cameraPosition – mCameraNode->getPosition()) * mTightness;

       mCameraNode->translate( displacement );

       Displacement = (targetPosition – mTargetNode->getPosition()) * mTightness;

       mTargetNode ->translate( displacement );   

}

};

 

在每一楨的楨監聽中,更變攝象機,角色和攝象機模式。

 

       Class SampleListener : public ExampleFrameListener

       {

       Protected:

              Character *mChar;

              ExtendedCamera *mExCamera;

              Unsigned int mMode;    // 攝象機模式,現在支持第一人稱,綁定的第三人稱攝象機和動態捕捉第三人稱攝象機

       Public:

              SampleListener(RenderWindow *win, Camera *cam) : ExampleFrameListener(win, cam)

              {

                     mChar = 0;

                     mExCamera = 0;

                     mMode = 0;

}

 

Void setCharacter(Character * character)

{

       mChar = character;

}

 

Void setExtendedCamera(ExtendedCamera *cam)

{

       mExCamera = cam;

}

 

Bool frameStarted( const FrameEvent& evt )

{

       mInputDevice->capture();

 

       if (mChar)

       {

              mChar->update(evt.timeSinceLastFrame, mInputDevice);

              if (mExCamera)

              {

                     Switch(mMode)

                     {

                            // 動態捕捉型第三人稱攝象機

                            case 0:

mExCamera->update(evt.timeSinceLastFrame, mChar->getCameraNode()->getWorldPosition(), mChar->getSightNode()->getWorldPosition());

break;

                                          // 綁定的第三人稱攝象機

                                          case 1:

                                                 mExCamera->update(evt.timeSinceLastFrame, Vector3(0, 200, 0), mChar->getSightNode()->getWorldPosition());

                                                 break;

                                          // 第一人稱攝象機

                                          case 2:

                                                 mExCamera->update(evt.timeSinceLastFrame, mChar->getWorldPosition(), mChar->getSightNode()->getWorldPosition());

                                                 break;

}

}

}

// F1鍵切換為動態捕捉型第三人稱攝象機

If (mInputDevice->isKeyDown(KC_F1))

{

       mMode = 0;

       if (mChar)

              static_cast<OgreCharacter* >(mChar)->setVisible(true);

       if (mExCamera)

       {

              If (mChar)

              {

mExCamera->instantUpdate(mChar->getCameraNode()->getWorldPosition(), mChar->getSightNode()->getWorldPosition());

}     

              mExCamera->setTightness(0.01f);      

}

}

//  F2切換為綁定的第三人稱攝象機

If( mInputDevice->isKeyDown(KC_F2))

{

       mMode = 1;

       if (mChar)

              static_cast<OgreCharacter*>(mChar)->setVisible(true);

       if (mExCamera)

       {

              If (mChar)

                     mExCamera->instanceUpdate(Vector3(0, 200, 0), mChar->getSightNode()->getWorldPosition());

              mExCamera->setTightness(0.01f);

}

}

 

// F3鍵切換為第一人稱攝象機

If (mInputDevice->isKeyDown(KC_F3))

{

       mMode = 2;

       if (mChar)

              static_cast<OgreCharacter*>(mChar)->setVisible(true);

       if(mExCamera)

{

              If (mChar)

              {

mExCamera->instantUpdate(mChar->getWorldPosition(), mChar->getSightNode()->getWorldPosition());

}     

              mExCamera->setTightness(1.0f); 

}

}

// 若按下ESC就退出

If (mInputDevice->isKeyDown(KC_ESCAPE))

       Return false;

 

Return true;

}

};

 

下面是一個App程序的樣本,如果你不理解這段代碼,你可以看一下其他的Ogre文章。

 

Class SampleApplication : public ExampleApplication

{

       Public:

              SampleApplication(){}

              ~ SampleApplication(){}

       Protected:

              // 創建場景

              Void createScene(void)

              {

                     // 設置環境光

                     mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.2));

                     // 創建一個點光源

                     Light* l = mSceneMgr->createLight(“MainLight”);

                     // 這個點光源使用默認設置

                     l->setType(Light::LT_DIRECTIONAL);

                     l->setDirection(-0.5, -0.5, 0);

                     // 攝象機位置

                     mCamera->setPosition(0, 0, 0);

                     // 為場景添加一些實體對象

                     SceneNode* razorNode;

                     Entity* razorEntity;

                     For (unsigned int i = 0; i< 30; ++i)

                     {

                            razorNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(StringConverter::toString(i), Vector3(Mesh::RangeRandom(-1000, 1000), 0, Math::RangeRandom(-1000, 1000)));

                            razorEntity = mSceneMgr->createEntity(StringConverter::toString(i), “razor.mesh”);

                            rezorNode->attachObject(razorEntity);

}

 

// 主角

OgreCharacter *ogre = new OgreCharacter(“Ogre 1”, mSceneMgr);

ExtendedCamera *exCamera = new ExtendedCamera(“Extended Camera”, mSceneMgr, mCamera);

// 楨監聽器用來管理主角和攝象機的更新和不同攝象機模式間的切換

mFrameListener = new SampleListener(mWindow, mCamera);

static_cast<SampleListener*>( mFrameListener)->setCharacter(ogre);

static_cast<SampleListener*>( mFrameListener)->setExtendedCamera(exCamera);

}

 

Void destroyScene(void){}

Void createFrameListener(void)

{

       // 放棄實例化我們自己的楨監聽器

       // mFrameListener = new SampleListener(mWindow, mCamera);

       mRoot->addFrameListener(mFrameListener);

}

};

 

注意:在createFrameListener()函數中,我們并沒有構造創建楨監聽器,所以不會有兩個監聽器。這是非常重要的,若我們創建兩個楨監聽器,這個程序將會當機。

 

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32

#define WIN32_LEAN_AND_MEAN

#include “windows,h”

 

INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT)

#else

Int main(int argc, char** argv)

#endif

{

       // 創建APP實例

       SampleApplication app;

Try

{ app.go(); }

Catch( Exception & e)

{

              #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32

       MessageBox( NULL, e.getFullDescription().c_str(), “An Exception has occurred!”, MB_OK | MB_ICONERROR );

       #else

       Fprintf(stderr, “An Exception has occurred: %s\n”, e.getFullDescription().c_str());

       #endif

}

Return 0;

}

 

l        結束語

希望這篇文章對你有用處,我會之后再更新它來進行更多的解釋說明。感謝您的閱讀。

Kencho

posts - 94, comments - 138, trackbacks - 0, articles - 94

Copyright © RichardHe

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产一区二区三区在线观看免费视频| 亚洲一级片在线观看| 免费在线日韩av| 久久久久久久久久久久久9999| 亚洲女同在线| 欧美亚洲日本一区| 久久国内精品视频| 免费欧美网站| 欧美日韩一区二区在线观看视频| 欧美视频不卡| 黄网动漫久久久| 99re6这里只有精品| 亚洲免费在线精品一区| 久久久久久久激情视频| 亚洲第一页中文字幕| 亚洲国产高清一区| 亚洲一区二区三区成人在线视频精品| 欧美一区永久视频免费观看| 久久天天躁狠狠躁夜夜av| 欧美成人按摩| 国产精品视频免费在线观看| 在线精品一区| 午夜欧美电影在线观看| 麻豆精品一区二区av白丝在线| 亚洲国产精品t66y| 午夜国产不卡在线观看视频| 免费久久精品视频| 国产精品一区二区视频 | 影音先锋国产精品| 一区二区欧美激情| 久久亚洲午夜电影| 夜久久久久久| 欧美不卡在线| 狠狠久久婷婷| 亚洲伊人伊色伊影伊综合网| 欧美a级片网| 欧美一级二区| 欧美性久久久| 亚洲美女啪啪| 欧美成人乱码一区二区三区| 亚洲性夜色噜噜噜7777| 欧美刺激性大交免费视频| 国产专区欧美精品| 欧美亚洲专区| 一区二区三区www| 欧美精品观看| 亚洲国语精品自产拍在线观看| 亚洲三级影片| 久久精品国产一区二区三区| 国产精品二区二区三区| 亚洲国产精品久久久久秋霞蜜臀 | 亚洲精品视频在线观看免费| 欧美一区网站| 亚洲综合日韩在线| 国产精品久久久久久久午夜片 | 欧美一区在线直播| 国产日韩亚洲| 久久精品观看| 羞羞色国产精品| 国产伦精品一区二区三区免费| 亚洲综合精品| 亚洲制服少妇| 国产一区欧美| 久久人人爽人人爽| 久久精品亚洲乱码伦伦中文| 国语自产精品视频在线看抢先版结局 | 亚洲精品在线视频观看| 欧美激情精品久久久久| 亚洲三级电影全部在线观看高清| 欧美国产成人精品| 欧美国产视频日韩| 在线天堂一区av电影| 一区二区三区欧美激情| 国产伦精品一区| 欧美成人激情视频| 欧美精品粉嫩高潮一区二区 | 亚洲小视频在线| 9l国产精品久久久久麻豆| 国产精品毛片高清在线完整版| 欧美一区二区日韩一区二区| 久久电影一区| 亚洲精品国精品久久99热| 日韩视频第一页| 国产精品有限公司| 欧美h视频在线| 欧美日韩综合在线| 久久久久久亚洲精品中文字幕| 久久免费99精品久久久久久| 亚洲精品中文字幕在线| 亚洲在线观看视频网站| 在线看日韩欧美| 日韩一级免费观看| 国产一区三区三区| 最新成人av在线| 亚洲欧美自拍偷拍| 亚洲欧美日韩一区二区三区在线| 亚洲综合色自拍一区| 在线欧美小视频| 亚洲日本乱码在线观看| 国产一区二区高清| 亚洲精品免费电影| 伊人久久婷婷| 亚洲在线第一页| 亚洲免费成人av电影| 午夜国产欧美理论在线播放| 亚洲精品久久久久久久久久久久久 | 久久aⅴ国产紧身牛仔裤| 亚洲日本中文| 久久gogo国模裸体人体| 亚洲一二三区精品| 蜜臀91精品一区二区三区| 亚洲欧美综合一区| 欧美激情第三页| 欧美激情成人在线视频| 国内精品久久久久影院优| 亚洲午夜激情网站| 亚洲视频在线观看免费| 免费观看一区| 毛片一区二区| 国内精品久久久久久久影视蜜臀| 亚洲午夜精品久久久久久浪潮| 亚洲伦理网站| 欧美大秀在线观看| 欧美激情视频网站| 1000部精品久久久久久久久| 欧美一区二区三区播放老司机| 亚洲在线1234| 欧美吻胸吃奶大尺度电影| 亚洲精品视频二区| 亚洲精品你懂的| 欧美99久久| 亚洲国产精品v| 亚洲二区视频在线| 噜噜噜在线观看免费视频日韩| 久久免费观看视频| 国内精品久久久久国产盗摄免费观看完整版| 亚洲一区二区动漫| 性感少妇一区| 国产亚洲欧美日韩日本| 亚洲欧美综合国产精品一区| 欧美在线观看网站| 国产在线精品二区| 久久久噜噜噜久久中文字免 | 亚洲午夜视频在线观看| 亚洲永久免费| 国产欧美日韩在线| 久久国产精品黑丝| 欧美成年人视频| 亚洲美女网站| 国产精品第2页| 亚洲欧美视频一区| 蜜桃精品一区二区三区| 亚洲精品国偷自产在线99热| 欧美视频成人| 欧美一区1区三区3区公司| 久久青草久久| 亚洲国产日韩一区二区| 欧美精品在线一区| 亚洲黄色成人| 久久成人羞羞网站| 国内精品久久久久久久影视蜜臀| 久久免费黄色| 亚洲日本aⅴ片在线观看香蕉| 国产精品99久久久久久人| 国产精品看片你懂得| 久久福利电影| 亚洲区国产区| 久久爱www久久做| 亚洲国内自拍| 国产精品婷婷| 免费国产自线拍一欧美视频| av成人免费观看| 久久久夜色精品亚洲| 亚洲精品一线二线三线无人区| 国产精品美女主播在线观看纯欲| 久久精品成人一区二区三区| 亚洲三级电影在线观看| 欧美在线亚洲一区| 99精品热视频| 黄色国产精品| 欧美婷婷久久| 美女诱惑黄网站一区| 亚洲一区二区免费视频| 最新69国产成人精品视频免费| 久久国产免费看| 亚洲天堂免费在线观看视频| 狠狠狠色丁香婷婷综合激情| 国产精品h在线观看| 欧美成人免费一级人片100| 亚洲男女自偷自拍图片另类| 亚洲人体1000| 欧美第一黄网免费网站| 久久精品夜色噜噜亚洲aⅴ| 一区二区三区久久精品| 亚洲国产一区二区三区青草影视| 国产午夜精品全部视频在线播放| 欧美特黄视频| 欧美日韩国产综合在线| 免费精品99久久国产综合精品| 久久精品一区二区国产|