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