摄像机的实现之美

1、基础的跟随摄像机

 摄像机的实现之美

为摄像机创建观察矩阵,需要三个参数:眼睛的位置(摄像机的位置)、摄像机观察目标,以及摄像机的上方向量。在基础跟随摄像机中,眼的位置可以设置为目标的水平和垂直偏移。

//tPso,tUp,tForward=位置、上方和前方向量
//hDist=水平跟随距离
//vDist=垂直跟随距离
function BasicFollowCamera(Vector3 tPos,Vector3 tUp,
                           Vector3 tForward,float hDist,float vDist)
//眼睛就是目标位置的偏移量
Vector3 eye=tPos-tForward*hDist+tUp*vDist
//摄像机向前的方向是从眼睛到目标
Vector3 cameraForward=tPos-eye
cameraForward.Normalize()

//叉乘计算出摄像机的左边及上方向量
Vector3 cameraLeft=CrossProduct(tUp,cameraForward)
cameraLeft.Normalize()
Vector3 cameraUp=CrossProduct(cameraForward,cameraLeft)
cameraUp.Normalize()

//CreateLookAt的参数为eye、target,以及up
return CreateLookAt(eye,tPos,cameraUp)
end

摄像机的实现之美

2、弹性跟随摄像机

摄像机的实现之美 摄像机的实现之美

class SpringCamera
   //水平和垂直跟随距离
   float hDist,vDist
   //弹性常量:越高表示越僵硬
   //一个好的初始值很大程度取决于你想要的效果
   float springConstant
   //阻尼常量由上面的值决定
   float dampConstant
   
   //速度和摄像机真实位向量
   Vector3 velocity,actualPosition

   //摄像机跟随的目标
   //(有目标的位置、向前向量、向上向量)
   GameObject target

   //最终的摄像机矩阵
   Matrix cameraMatrix
 
   //这个帮助函数从真实位置及目标计算出摄像机矩阵
   function ComputeMatrix()
       //摄像机的前向是从真实位置到目标位置
       Vector3 cameraForward=target.position-actualPosition
       cameraForward.Normalize()
       //叉乘计算出摄像机左边、然后计算出上方
       Vector3 cameraLeft=CrossProduct(target.up,cameraForward)
       cameraLeft.Normalize()
       Vector3 cameraUp=CrossProduct(cameraForward,cameraLeft)
       cameraUp.Normalize()

       //CreateLookAt参数为eye、target及up
       cameraMatrix=CreateLookAt(actualPosition,target.position,cameraUp)
    end

    //初始化常量及摄像机,然后初始化朝向
    function Initialize(GameObject myTarget,float mySpringConstant,float  myHDist,float myVDist) 
        target=myTarget
        springConstant=mySpringConstant
        hDist=myHDist
        vDist=myVDist

        //阻尼常量来自于弹性常量
        dampConstant=2.0f*sqrt(springConstant)

        //起初,设置位置为理想位置
        //就跟基础跟随摄像机的眼睛位置一样
        actualPosition=target.position-target.forward*hDist+target.up*vDist
        //初始化摄像机速度为0
        velocity=vector3.Zero
        //设置摄像机矩阵
        ComputeMatrix()
      end

      function Update(float deltaTime)
         //首先计算理想位置
         Vector3 idealPosition=target.position-target.forward*hDist+target.up*vDist
         //计算从理想位置到真实位置的向量
         Vector3 displacement=actualPosition-idealPosition
         //根据弹簧计算加速度,然后积分
         Vector3 springAccel=(-springConstant*displacement)-(dampConstant*velocity)
         velocity+=springAccel*deltaTime
         actualPosition+=velocity*deltaTime
         //更新摄像机矩阵
         ComputeMatrix()
       end
end

弹性摄像机的最大好处就是当目标对象旋转的时候,摄像机会有一定的延迟才开始转动。旋转出来的效果要比基础跟随摄像机要好得多。弹性摄像机效果比基础跟随摄像机好很多,都是计算量没多多少。

3、旋转摄像机

摄像机的实现之美

class OrbitCamera
   //摄像机向上的向量
   Vector3 up
   //目标偏移
   Vector3 offset
   //目标对象
   GameObject target
   //最终的摄像机矩阵
   Matrix cameraMatrix
  
   //初始化摄像机状态
   function Initiallize(GameObject myTarget,Vector3 myOffset)
       //在y轴朝上的世界里,up向量就是y轴
       up=Vector3(0,1,0)

       offset=myOffset
       target=myTarget

        //CreateLookAt参数为eye、target和up
        cameraMatrix=CreateLookAt(target.position+offset,target.position,up)
     end

     //根据这一帧的yaw/pitch增量角度进行更新
     function Update(float yaw,float pitch)
         //创建一个关于世界向上的四元数
         Quaternion quatYaw=CreateFromAxisAngle(Vector3(0,1,0),yaw)
         //通过这个四元数变换摄像机偏移
         offset=Transform(offset,quatYaw)
         up=Transform(up,quatYaq)

         //向前向量就是target.position-(target.position+offset)
         //刚好就是-offset
         Vector3 forward=-offset
         forward.Normalize()
         Vector3 left=CrossProduct(up,forward)
         left.Normalize()

         //创建关于摄像机左边旋转的四元数值
         Quaternion quatPitch=CreateFromAxisAngle(left,pitch)
         //通过这个四元数变化摄像机偏移
         offset=Transform(offset,quatPitch)
         up=Transform(up,quatPitch)
         //现在计算矩阵
         cameraMatrix=CreateLookAt(target.position+offset,target.position,up)
      end
end


在一些游戏里面,可能同时想要有弹性摄像机和手动的旋转摄像机。两种方法完全可以组合起来得到
跟随而且旋转的特性。

4、第一人称摄像机

摄像机的实现之美

class FirstPersonCamera
    //以角色位置为原点的摄像机偏移
    //对于y轴向上的世界,向上就是(0,value, 0)
    Vector3 verticalOffset
    //以摄像机为原点的目标位置偏移
    //对于z轴向前的世界,向前就是(0,0,value)
    Vector3 targetOffset
    //总的偏航和俯视角度
    float totalYaw,totalPitch
    //摄像机所在的玩家
    GameObject player
    //最终的摄像机矩阵
    Matrix cameraMatrix

    //初始化所有摄像机参数
    function Initialize(GameObject myPlayer,Vector3 myVerticalOffset,Vector3 myTargetOffset)
        player=myPlayer
        verticalOffset=myVerticalOffset
        targetOffset=myTargetOffset

        //最开始,没有任何偏航和俯视
        totalYaw=0
        totalPitch=0
  
        //计算摄像机矩阵
        Vector3 eye=player.position+verticalOffset
        Vector3 target=eye+targetOffset
        //在y轴向上的世界里
        Vector3 up=Vector3(0,1,0)
        cameraMatrix=CreateLookAt(eye,target,up)
     end
     //根据这一帧的增量偏航和俯视进行更新
     function Update(float yaw,float pitch)
         totalYaw+=yaw;
         totalPitch+=pitch

         //对俯视进行Clamp
         //在这种情况下,范围为角度45°(弧度约为0.78)
         totalPitch=Clamp(totalPitch,-0.78,0.78)

         //目标在旋转之前偏移
         //真实偏移则是在旋转之后
         Vector3 actualOffset=targetOffset

         //关于y轴进行偏航旋转,旋转真实偏移
         Quaternion quatYaw=CreateFromAxisAngle(Vector3(0,1,0),totalYaw)
         actualOffset=Transform(actualOffset,quatYaw)

         //为了俯视计算左边向量
         //前向就是偏航之后真实偏移(经过正规化)
         Vector3 forward-actualOffset
         forward.Normalize()
         Vector3 left=CrossProduct(Vector3(0,1,0),forward)
         left.Normalize()

         //关于左边进行俯视,旋转真实偏移
         Quaternion quatPitch=CreateFromAxisAngle(left,totalPitch)
         actualOffset=Transform(actualOffset,quatPitch)

         //现在构造摄像机矩阵
         Vector3 eye=player.position+verticalOffset
         Vector3 target=eye+actualOffset
         //在这种情况下,我们可以传递向上向量,因为我们永远向上
         cameraMatrix=CreateLookAt(eye,target,Vector3(0,1,0))
      end
end

 







 

 

 

 

上一篇:登陆页面html


下一篇:[机翻]An eagle eye view into the Mesa source tree[翻译]