最近想仿一个CS游戏,在实现用鼠标控制摄像机旋转时遇到了难题。在网上搜了些资料,但感觉描述不清楚,答非所问。有的只贴上了代码,没有对相关技术予以说明,实在很难读懂其核心技术。昨天弄了一天,结果旋转的很糟糕,就像无头苍蝇似的,无法控制。今天早晨躺在床上想了一下,突然明白错在什么地方了。坐标旋转的时候要绕Y轴旋转,而不能饶Up方向旋转,因为Up会随着绕right轴旋转而改变,所以整体旋转实难控制。想到这里,就迫不急待的起床了,吃完早点,到实验楼修正了下旋转方式,结果一切正常!
设我们的摄像机有三个方向look、up、right,则我们可以控制摄像机在三维空间中做任意角度的变换。如果要用鼠标来控制摄像机旋转,那么我们需要根据鼠标的移动量来更新这三个方向向量,从而达到摄像机跟随鼠标移动而变换。
鼠标的移动是二维的:水平移动(x方向),垂直移动(y方向)(注:此处xy是窗口设备坐标系。)。那么鼠标的一个微小移动量总可以分解成x和y方向的移动分量,我们根据y方向的移动分量,来设制摄像机绕right方向进行相应角度的旋转,即可实现摄像机视野上下移动;而根据x方向的移动分量,来设置摄像机绕Y轴(世界坐标系)方向进行相应角度的旋转,即可实现摄像机视野水平移动(左右移动)。
以下是算法伪代码:
point = getCursorPos() dx = point.x - pointOld.x dy = point.y - pointOld.y pointOld = point rotationRight(camera,dy*scaleY)//scale为缩放系数 rotationY(camera,dx*scaleX)
pointOld.x = wndWidth/2 pointOld.y = wndHeight/2 point = getCursorPos() dx = point.x - pointOld.x dy = point.y - pointOld.y rotationRight(camera,dy*scaleY) rotationY(camera,dx*scaleX) setCursorPos(pointOld)//锁定坐标到窗口中央此时,需要使鼠标隐身,否则会看到它不停地闪烁。如果还想加入一个射击靶心,可以简单的在锁定点贴一张纹理,或者根据鼠标选取算法,在选取射线上使用“广告板”技术绘制一张纹理。
通常摄像机上下旋转的时候,我们不想让他拥有360°的灵活性,而应该限制在某一角度范围如(-pi/4 ~ pi/4)。我们需要记录它的相对旋转角度,如果设初始状态时摄像机上下旋转的角度为0,那么我们需要累加它的所有上下旋转角度值(注:上为正、下位负,或者反过来),如果角度值超过界限范围,则将角度值绑定到界限边界。
rotationRight(camera,angle) { fRotAngRight += angle if(fRotAngRight > bound) fRotAngRight = bound else if(fRotAngRight < -bound) fRotAngRight = -bound }如果我们的旋转动作都由旋转角度来替代,那么程序中的look、right、up向量将会无效,如果要取得方向向量,则要根据旋转角度和初始方向状态进行相应的旋转计算后才可得到。
本文仅代表个人观点,不代表通用技术。希望各位高手可以提供自己的看法,我们共同交流。希望本文对大家有所帮助。