ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

摄像机的实现之美

2021-06-17 14:08:25  阅读:230  来源: 互联网

标签:float eye target 实现 Vector3 之美 up 摄像机


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

 







 

 

 

 

标签:float,eye,target,实现,Vector3,之美,up,摄像机
来源: https://blog.51cto.com/u_15273495/2915277

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有