• <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>

            的筆記

            隨時隨地編輯

            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

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

            1.chase攝像頭的基本對象

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


            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在幀循環(huán)中處理的唯一依據(jù)。

            3.幀循環(huán)邏輯

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

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

            4.角色的移動

                  按鍵事件決定了角色的移動方向,用keydirection表示角色在local中的移動方向,用goaldirection表示角色在world中的移動。在幀循環(huán)中根據(jù)這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;
            }

                幀循環(huán)中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的平移操作:
            幀循環(huán)中,相機update操作時,將pivot設置到角色的肩膀處
            pivot的yaw、pitch操作:
            鼠標move事件中,根據(jù)鼠標的x、y坐標做yaw、pitch操作

            goal的平移操作:
            鼠標move事件中,根據(jù)鼠標的z坐標進行l(wèi)oca-z的平移
            goal不會有l(wèi)ocal旋轉操作

            相機的操作:
            幀循環(huán),相機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.角色根據(jù)WASD方向與自身方向的合成移動,而不是與相機方向合成的移動

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

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

            本節(jié)完整源碼: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 的筆記 閱讀(2436) 評論(0)  編輯 收藏 引用

            亚洲中文字幕久久精品无码APP | 久久天天躁狠狠躁夜夜avapp| 国产精品狼人久久久久影院| 无码人妻精品一区二区三区久久久| 久久午夜综合久久| 欧美色综合久久久久久| 99久久夜色精品国产网站| 久久精品九九亚洲精品| 国产精品成人久久久久三级午夜电影| 久久无码精品一区二区三区| 亚洲欧洲精品成人久久曰影片| 日日躁夜夜躁狠狠久久AV| 国产精品久久久久影院色| 日本精品久久久久久久久免费| 国产A三级久久精品| 色婷婷综合久久久中文字幕| 久久久久九九精品影院| 无码日韩人妻精品久久蜜桃| 久久影院午夜理论片无码| 国产午夜精品久久久久免费视| 久久亚洲天堂| 久久久久久国产精品无码超碰| 欧美国产成人久久精品| 久久精品国产99国产精品澳门| 性做久久久久久久久久久| 亚洲国产另类久久久精品黑人 | 久久亚洲国产精品123区| 狼狼综合久久久久综合网| 久久精品二区| 久久久国产精品| 久久久久久噜噜精品免费直播| 人人狠狠综合久久亚洲88| 99蜜桃臀久久久欧美精品网站| 2020国产成人久久精品| 国产一区二区精品久久岳| 亚洲色大成网站www久久九| 久久久久国产精品人妻| 久久精品人人做人人爽电影| 久久午夜无码鲁丝片秋霞 | 欧美成人免费观看久久| 久久精品人妻一区二区三区|