需求背景
工作中需要使用 threejs 制作一个第一人称的 viewer,在使用 threejs 的 flyControls 时发现一些和需求不一样的情景。
主要的问题就是拖拽查看时相机在拖拽后会导致上方向的变化从而导致视角变化很奇怪,所以需要改造一下原本的 FlyControl。
既然要改造那就肯定要先解析 FlyControls 的源码了
FlyControls的功能
FlyControls 实现了一个类似第一人称视角通过 WASD 来调整相机前进的基本控制器。
例子:https://threejs.org/examples/#misc_controls_fly
文档:https://threejs.org/docs/index.html?q=fly#examples/zh/controls/FlyControls
可以看到上图 WASD 控制移动,RF 控制上下移动,QE 旋转相机,方向键上下左右可以控制视角。
也可以用鼠标偏移位置自动旋转视角
源码分析属性声明
地址 :
https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/FlyControls.js
首先 FlyControls 继承自 EventDispatcher ,EventDispatcher 是事件调度器。
主要是用于 FlyControls 的事件信息传递用。
构造函数中一个是 object 也就是控制的摄像机对象从 TS 定位文件中可以看出是一个Camera或者继承自Camera的对象。
domElement 则是当前 threejs renderer 绘制的 dom 元素
接下来就是一系列变量的定义
其中 movmentSpeed,rollSpeed 是控制相机移动和旋转的速度的
dragToLook 则是我们需求中需要的拖拽使相机视角发生变化,可以看到这里默认是 false。
autoForward 是自动向前
EPS 应该是最小误差修正用的
可以看到这里还用 lastQuaternion 和 lastPosition 记录了最后相机的四元组和位置信息
tmpQuaternion 就是临时保存用的一个四元组
剩下就是一些状态值
源码分析事件监听
在代码最底部可以看到 FlyControls 监听了7个事件分别对应一系列操作。
先从第一个keydown分析
1、一开始判断是否按下了 alt 键和是否启用了控制器
2、然后根据按键的键码分别设置 moveState 的状态,其中 shift 对移动速度进行了修改
3、然后就是最关键的 updateMovementVector 和 updateRotationVector,这两个之后进行分析。
这里 keyup 和 keydown 类似就不过多做分析
然后是鼠标操作三兄弟
从 pointerdown 可以看出来是根据 dragToLook 来进行不同的操作。
如果是拖拽调整视角就修改 status 的值
如果不是则根据按下的鼠标左键还是又键修改 moveState 的状态。
紧接着pointermove事件中:
依旧如果不是使用拖拽查看或者 status大于0 (这里的 status>0 是由向前的 pointerdown 修改的,也就是可以看做是否按下了鼠标)
然后就是这个 getContainerDimensions ,其实就是查看这个当前的 viewer 是不是在 docment 对象,返回相应的大小和偏移值
而 halfWidth ,halfHeight 就是当前 viewer 可视区域一半的宽高。
-( event.pageX - container.offset[ 0 ] ) 和 ( ( event.pageY - container.offset[ 1 ] ) 是鼠标在当前可视区域的相对坐标,
其值减去一半的宽度后,其实就可以视作鼠标相对于可视区域中心点的相对位置了。
以x轴来举例可以看出来 ( event.pageX - container.offset[ 0 ] ) - halfWidth 则是红线部分则是鼠标到中心点的距离。
然后除以 halfWidth 则是一个归一化处理,相当于把鼠标距离中心点位置的值域控制在0到1之间了,最后在修改 moveState。
最后pointerup事件则是将状态还原
在此之后 可以看到 updateMovementVector 和 updateRotationVector 实质上是修改了 moveVector 和 rotationVector
最后
再根据之前设置的速度和旋转值以及 rotationVector 和 moveVector 来控制相机的位置以及旋转。
最后的判断则是看移动和旋转的值是否太小了。
太小就进行忽略。
分析
那么这个控制器为什么会造成拖拽后上方向发生变化呢,其实从上面代码的分析不难看出。
先将鼠标向上旋转一个角度
再将鼠标朝右旋转
最后再朝下拖动鼠标时
此时的相机左方向轴已经不在x轴与y轴构成的平面上了。
所以相机上方向发生了变化。
其根本原因是相机左右旋转时旋转轴是以自身上方向为旋转轴造成的。
如果要保持相机上方向一致的情况下旋转视角应该以z轴作为相机旋转的旋转轴。
这样相机怎么旋转都能保持上方向一致了。
– 欢迎点赞、关注、转发、收藏【我码玄黄】,gonghao 同名
本文暂时没有评论,来添加一个吧(●'◡'●)