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

的筆記

隨時隨地編輯

Chase camera筆記

參考資料:
 - ogre1.72 character sample
 - Creating a simple first-person camera system
 - 3rd person camera system tutorial
 - Make A Character Look At The Camera         
   Using quaternions and SLERP to make a character look at a camera (or any other object for that matter) naturally, with constraints on head movement

I.character sample

本節是對ogre 1.72 sample character 的分析,源碼見本節尾的說明。

1.chase攝像頭的基本對象

對象關系圖
   
     
      goal作為pivot的子節點,放置在(0 ,0 , 15)處,也就是說goal永遠會在pivot的正后方,不離不棄,。pivot就是那美麗的月亮女神,goal是永遠的追隨者。camNode是獵殺者,只有取代goal的地位(postion,direct)才能贏得月亮女神。任何時刻camNode都在追逐goal這個目標。這也是chase攝像機的基本原理。
      這里將pivot放置在角色的肩膀處,在幀循環里同步這個位置永遠不變。


2.鼠標邏輯

MouseMove事件影響
pitch ---  只影響pivot的pitch。
yaw ---    只影響pivot的yaw。
zoom --- 只影響goal的local postion,決定了goal與pivot的z向距離。goal永遠在pivot的正后方,也就是只在pivot的z軸上移動。

      鼠標的移動只會造成pivot的yaw和pitch,以及goal的local-z的移動。同角色的移動是沒有關系的。
code:

void injectMouseMove(const OIS::MouseEvent& evt)
{
    
// update camera goal based on mouse movement
    updateCameraGoal(-0.05f * evt.state.X.rel, -0.05f * evt.state.Y.rel, -0.0005f * evt.state.Z.rel);
}


    
void updateCameraGoal(Real deltaYaw, Real deltaPitch, Real deltaZoom)
{
    mCameraPivot
->yaw(Degree(deltaYaw), Node::TS_WORLD);

    
// bound the pitch
    if (!(mPivotPitch + deltaPitch > 25 && deltaPitch > 0&&
        
!(mPivotPitch + deltaPitch < -60 && deltaPitch < 0))
    
{
        mCameraPivot
->pitch(Degree(deltaPitch), Node::TS_LOCAL);
        mPivotPitch 
+= deltaPitch;
    }

    
    Real dist 
= mCameraGoal->_getDerivedPosition().distance(mCameraPivot->_getDerivedPosition());
    Real distChange 
= deltaZoom * dist;

    
// bound the zoom
    if (!(dist + distChange < 8 && distChange < 0&&
        
!(dist + distChange > 25 && distChange > 0))
    
{
        mCameraGoal
->translate(00, distChange, Node::TS_LOCAL);
    }

}
      鼠標移動最終的結果是改變了goal在world中的position和direction,這個作為camera在幀循環中處理的唯一依據。

3.幀循環邏輯

更新角色
    取得按鍵方向矢量,根據這個矢量設置角色的positon,direction
更新攝相機
    將永遠的中心月亮女神pivot放到角色的肩膀上。(女神的圣斗士goal會永遠在pivot女神的正后方,,同時goal的獵殺者camNode也會死死緊逼)
    獵殺者camNode用自己的速度向goal前進一步
    獵殺者將視線對準月亮女神pivot(雖然postion是向goal逼近,但是方向卻向著永遠的中心月亮女神pivot)

至此chase攝像機的基本實現原理水落石出。無非就是女神的圣斗士被獵殺者時刻緊追,獵殺者死死的盯住女神用目光表示內容,用行動追逐女神的斗士。

4.角色的移動

      按鍵事件決定了角色的移動方向,用keydirection表示角色在local中的移動方向,用goaldirection表示角色在world中的移動。在幀循環中根據這2個方向移動角色------用角色自己的速度移動。

按鍵決定了移動方向:
// player's local intended direction based on WASD keys
Vector3 mKeyDirection;
// actual intended direction in world-space
Vector3 mGoalDirection;

void injectKeyDown(const OIS::KeyEvent& evt)
{
    
// keep track of the player's intended direction
    if (evt.key == OIS::KC_W) mKeyDirection.z = -1;
    
else if (evt.key == OIS::KC_A) mKeyDirection.x = -1;
    
else if (evt.key == OIS::KC_S) mKeyDirection.z = 1;
    
else if (evt.key == OIS::KC_D) mKeyDirection.x = 1;
}


void injectKeyUp(const OIS::KeyEvent& evt)
{
    
// keep track of the player's intended direction
    if (evt.key == OIS::KC_W && mKeyDirection.z == -1) mKeyDirection.z = 0;
    
else if (evt.key == OIS::KC_A && mKeyDirection.x == -1) mKeyDirection.x = 0;
    
else if (evt.key == OIS::KC_S && mKeyDirection.z == 1) mKeyDirection.z = 0;
    
else if (evt.key == OIS::KC_D && mKeyDirection.x == 1) mKeyDirection.x = 0;
}

    幀循環中update角色的position和direction:

//! 在世界坐標系中,取得角色將要面對的方向
// calculate actually goal direction in world based on player's key directions
mGoalDirection += mKeyDirection.z * mCameraNode->getOrientation().zAxis();
mGoalDirection 
+= mKeyDirection.x * mCameraNode->getOrientation().xAxis();

mGoalDirection.y 
= 0;
mGoalDirection.normalise();

if((mKeyDirection != Vector3::ZERO))
{
    
//! 角色的正前方
    Vector3 charFront = mBodyNode->getOrientation().zAxis();
    Quaternion toGoal 
= charFront.getRotationTo(mGoalDirection);

    
// calculate how much the character has to turn to face goal direction
    Real yawToGoal = toGoal.getYaw().valueDegrees();
    
// this is how much the character CAN turn this frame
    Real yawAtSpeed = yawToGoal / Math::Abs(yawToGoal) * deltaTime * TURN_SPEED;
    
// reduce "turnability" if we're in midair
    if (mBaseAnimID == ANIM_JUMP_LOOP) yawAtSpeed *= 0.2f;

    
//! 限制旋轉角度,不要旋轉過量
    
// turn as much as we can, but not more than we need to
    if (yawToGoal < 0
    
{
        yawToGoal 
= std::min<Real>(0, std::max<Real>(yawToGoal, yawAtSpeed)); 
        
//yawToGoal = Math::Clamp<Real>(yawToGoal, yawAtSpeed, 0);
    }

    
else if (yawToGoal > 0)
    
{
        yawToGoal 
= std::max<Real>(0, std::min<Real>(yawToGoal, yawAtSpeed)); 
        
//yawToGoal = Math::Clamp<Real>(yawToGoal, 0, yawAtSpeed);
    }

    
    
//! 角色yaw操作
    mBodyNode->yaw(Degree(yawToGoal));

    
//! 每次按鍵動作,角色都要用當前速度往正前方移動
    
// move in current body direction (not the goal direction)
    mBodyNode->translate(00, deltaTime * RUN_SPEED * mAnims[mBaseAnimID]->getWeight(),Node::TS_LOCAL);
}

 


5.各種坐標系變換總結

pivot的平移操作:
幀循環中,相機update操作時,將pivot設置到角色的肩膀處
pivot的yaw、pitch操作:
鼠標move事件中,根據鼠標的x、y坐標做yaw、pitch操作

goal的平移操作:
鼠標move事件中,根據鼠標的z坐標進行loca-z的平移
goal不會有local旋轉操作

相機的操作:
幀循環,相機update時,相機相goal平移逼近,并lookat pivot

角色的平移:
角色的旋轉,角色只會有yaw操作。角色從當前方向向按鍵和相機的矢量合成的目標方向逼近
角色在方向鍵keydirection不為0的時候,完成yaw操作后,向當前+z方向移動

6.修改到第一人稱視角

相機始終在角色的背后,正對角色。只需修改代碼中的updateCamera即可:
void SinbadCharacterController::updateCamera(Real deltaTime)
{
    
// place the camera pivot roughly at the character's shoulder
    mCameraPivot->setPosition(mBodyNode->getPosition() + Vector3::UNIT_Y * CAM_HEIGHT);
    
    
//! 將pivot對準角色的正前方,注意此時相機的+Z必須和角色的+Z相反,因為相機時從+Z看向-Z的
    
//! 這樣修改后,就完成了一個第一人稱的相機,和魔獸世界類似
    
//! W鍵始終讓角色往自身正前方走,而不是相機的正前方
    Vector3 front = mCameraPivot->getOrientation().zAxis();
    Vector3 goal  
= -mBodyNode->getOrientation().zAxis();
    Quaternion toGoal 
= front.getRotationTo(goal);
    Real yawToGoal 
= toGoal.getYaw().valueDegrees();
    mCameraPivot
->yaw(Degree(yawToGoal) , Node::TS_WORLD );

    
// move the camera smoothly to the goal
    Vector3 goalOffset = mCameraGoal->_getDerivedPosition() - mCameraNode->getPosition();

    mCameraNode
->translate(goalOffset * deltaTime * 1.0f);
    
// always look at the pivot
    mCameraNode->lookAt(mCameraPivot->_getDerivedPosition(), Node::TS_WORLD);
}
只是增加了幾行代碼,讓pivot的front與角色的front在一個平面,示意圖如下:

7.角色根據WASD方向與自身方向的合成移動,而不是與相機方向合成的移動

updateBody中方向合成的代碼
mGoalDirection += mKeyDirection.z * mCameraNode->getOrientation().zAxis();
mGoalDirection 
+= mKeyDirection.x * mCameraNode->getOrientation().xAxis();

本來以為將紅色字體處標識符替換為“mBodyNode”即可。運行時發現方向還算正常,但是角色會發生嚴重的角色抖動。不得其解。

本節完整源碼:https://3dlearn.googlecode.com/svn/trunk/Samples/Ogre/sinbad
此源碼來自ogre 1.72 sample character:https://bitbucket.org/sinbad/ogre/src/d1f2eab81f08/Samples/Character/

posted on 2011-06-15 12:15 的筆記 閱讀(2447) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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在线| 一区二区久久| 日韩一区二区精品葵司在线| 农夫在线精品视频免费观看| 91久久在线视频| 亚洲黄色天堂| 欧美人与性动交a欧美精品| 一个人看的www久久| 这里只有精品视频| 国产麻豆日韩| 久久综合99re88久久爱| 久久亚洲综合网| 亚洲精品一区二| 中文日韩在线| 韩国av一区| 亚洲精品乱码久久久久久| 欧美日韩一区二区三区四区在线观看| 亚洲欧美国产精品桃花| 久久动漫亚洲| 亚洲毛片在线免费观看| 亚洲一区自拍| 亚洲电影欧美电影有声小说| 亚洲毛片一区| 国产视频观看一区| 亚洲经典在线| 国产日韩欧美在线播放| 亚洲国产精品成人va在线观看| 欧美三级乱人伦电影| 美腿丝袜亚洲色图| 欧美日韩一区二区三区四区五区| 久久精品成人一区二区三区蜜臀| 欧美xx视频| 久久久免费观看视频| 欧美人妖在线观看| 久久全国免费视频| 国产精品久久久久久久久久久久| 久久久蜜桃精品| 欧美午夜精品理论片a级大开眼界 欧美午夜精品理论片a级按摩 | 欧美一区二区| 欧美激情bt| 久久久久久久久久久久久9999| 欧美日韩国产不卡| 美乳少妇欧美精品| 国产午夜精品一区二区三区欧美 | 亚洲精品国精品久久99热一| 国产一区二区黄| 亚洲乱码国产乱码精品精天堂| 黑人极品videos精品欧美裸| 亚洲色诱最新| 日韩一级在线观看| 欧美成人首页| 欧美承认网站| 精品成人在线| 欧美一二区视频| 午夜在线播放视频欧美| 欧美日韩一区二区在线| 亚洲国内精品在线| 亚洲国产专区| 久久午夜av| 猛男gaygay欧美视频| 加勒比av一区二区| 欧美在线日韩| 久久国产视频网站| 国产美女高潮久久白浆| 中文精品99久久国产香蕉| 亚洲视频精选在线| 欧美日韩一区三区四区| 99精品欧美一区二区三区| 一区二区不卡在线视频 午夜欧美不卡'| 久久一区二区三区超碰国产精品| 巨乳诱惑日韩免费av| 国产一级精品aaaaa看| 香蕉av福利精品导航| 欧美中文在线观看国产| 国产一区二区0| 久久九九免费| 欧美成人在线免费视频| 亚洲二区免费| 欧美二区视频| 一本综合久久| 亚洲欧美在线免费| 国产一区二区三区免费观看| 久久国产精彩视频| 嫩草影视亚洲| 亚洲免费久久| 国产精品久久二区二区| 亚洲欧美成人一区二区三区| 久久久国产午夜精品| 亚洲国产精品成人精品| 欧美激情中文字幕在线| 一区二区三区四区五区视频| 性欧美8khd高清极品| 黄色日韩网站| 欧美日韩国产不卡| 欧美一区二区三区啪啪| 亚洲电影免费观看高清完整版在线| 亚洲精品综合久久中文字幕| 欧美视频日韩视频| 久久激情五月丁香伊人| 欧美成人免费播放| 亚洲欧美日韩综合| 狠狠色2019综合网| 欧美日韩网站| 久久久久网址| 在线性视频日韩欧美| 久久亚洲国产成人| 一区二区免费在线播放| 国产一区二区电影在线观看| 欧美精品手机在线| 久久精品国产一区二区电影| 亚洲国产一区二区三区a毛片 | 国产午夜精品视频免费不卡69堂| 免费成人黄色| 亚洲综合视频一区| 亚洲黄色成人久久久| 欧美一区二区三区视频在线 | 亚洲国产精品小视频| 欧美三级乱码| 欧美成人黄色小视频| 午夜精品一区二区三区在线视| 亚洲激情自拍| 蜜臀a∨国产成人精品| 亚洲女与黑人做爰| 日韩午夜电影av| 精品51国产黑色丝袜高跟鞋| 国产精品视频观看| 欧美精品一区在线| 久久欧美中文字幕| 香蕉尹人综合在线观看| 中文无字幕一区二区三区| 欧美风情在线| 蜜臀av在线播放一区二区三区| 欧美一区二区成人6969| 亚洲网站在线| 在线亚洲一区观看| 日韩一级欧洲| 亚洲免费av网站| 在线看国产一区| 尤物九九久久国产精品的特点| 国产精品视频yy9099| 欧美日韩四区| 欧美性感一类影片在线播放| 欧美精品一区二区三区在线看午夜| 久久久美女艺术照精彩视频福利播放 | 亚洲一区二区高清视频| 一区二区不卡在线视频 午夜欧美不卡'| 一区二区三区在线看| 在线免费观看一区二区三区| 国产一区二区三区四区老人| 国产日产高清欧美一区二区三区| 国产日韩精品视频一区| 国产日韩欧美精品一区| 国产视频欧美视频| 国产一区二区三区高清| 国产一区二区日韩精品| 曰韩精品一区二区| 91久久精品网| 亚洲视频一区在线观看| 亚洲欧美激情诱惑| 久久久久国产精品一区| 免费观看亚洲视频大全| 亚洲大胆人体视频| 亚洲精品欧美日韩| 亚洲无亚洲人成网站77777| 午夜精品区一区二区三| 久久久久久久一区| 欧美成人首页| 欧美日韩在线三级| 国产一区视频网站| 亚洲大胆人体视频| 亚洲无限av看| 久久全国免费视频| 亚洲国产精品久久久| 99视频精品全国免费| 亚洲欧美一区二区原创| 免费久久99精品国产| 欧美日韩国内| 国产在线播放一区二区三区| 亚洲国产精品一区二区www| 中文日韩在线视频| 久久一区激情| 日韩小视频在线观看| 新狼窝色av性久久久久久| 免费日韩一区二区| 国产精品大片wwwwww| 狠狠色丁香久久综合频道| 在线午夜精品| 免费的成人av| 亚洲一级黄色av| 欧美成人免费在线视频| 国产乱人伦精品一区二区| 亚洲美女在线一区| 久久久久综合网| 99riav1国产精品视频| 久久国产黑丝| 国产精品美女久久久| 亚洲欧洲日夜超级视频| 久久精品视频va| 99精品欧美一区二区蜜桃免费|