编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

Three.js开发秘籍:FlyControls的拖拽视角问题解决方案

wxchong 2024-08-16 06:07:39 开源技术 18 ℃ 0 评论

需求背景

工作中需要使用 threejs 制作一个第一人称的 viewer,在使用 threejsflyControls 时发现一些和需求不一样的情景。

主要的问题就是拖拽查看时相机在拖拽后会导致上方向的变化从而导致视角变化很奇怪,所以需要改造一下原本的 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 继承自 EventDispatcherEventDispatcher 是事件调度器。

主要是用于 FlyControls 的事件信息传递用。

构造函数中一个是 object 也就是控制的摄像机对象从 TS 定位文件中可以看出是一个Camera或者继承自Camera的对象。

domElement 则是当前 threejs renderer 绘制的 dom 元素

接下来就是一系列变量的定义

其中 movmentSpeedrollSpeed 是控制相机移动和旋转的速度的

dragToLook 则是我们需求中需要的拖拽使相机视角发生变化,可以看到这里默认是 false

autoForward 是自动向前

EPS 应该是最小误差修正用的

可以看到这里还用 lastQuaternionlastPosition 记录了最后相机的四元组和位置信息

tmpQuaternion 就是临时保存用的一个四元组

剩下就是一些状态值

源码分析事件监听

在代码最底部可以看到 FlyControls 监听了7个事件分别对应一系列操作。

先从第一个keydown分析

1、一开始判断是否按下了 alt 键和是否启用了控制器

2、然后根据按键的键码分别设置 moveState 的状态,其中 shift 对移动速度进行了修改

3、然后就是最关键的 updateMovementVectorupdateRotationVector,这两个之后进行分析。

这里 keyupkeydown 类似就不过多做分析

然后是鼠标操作三兄弟

pointerdown 可以看出来是根据 dragToLook 来进行不同的操作。

如果是拖拽调整视角就修改 status 的值

如果不是则根据按下的鼠标左键还是又键修改 moveState 的状态。

紧接着pointermove事件中

依旧如果不是使用拖拽查看或者 status大于0 (这里的 status>0 是由向前的 pointerdown 修改的,也就是可以看做是否按下了鼠标)

然后就是这个 getContainerDimensions ,其实就是查看这个当前的 viewer 是不是在 docment 对象,返回相应的大小和偏移值

halfWidthhalfHeight 就是当前 viewer 可视区域一半的宽高。

-( event.pageX - container.offset[ 0 ] )( ( event.pageY - container.offset[ 1 ] ) 是鼠标在当前可视区域的相对坐标,

其值减去一半的宽度后,其实就可以视作鼠标相对于可视区域中心点的相对位置了。

x轴来举例可以看出来 ( event.pageX - container.offset[ 0 ] ) - halfWidth 则是红线部分则是鼠标到中心点的距离。

然后除以 halfWidth 则是一个归一化处理,相当于把鼠标距离中心点位置的值域控制在0到1之间了,最后在修改 moveState

最后pointerup事件则是将状态还原

在此之后 可以看到 updateMovementVectorupdateRotationVector 实质上是修改了 moveVectorrotationVector

最后

再根据之前设置的速度和旋转值以及 rotationVectormoveVector 来控制相机的位置以及旋转。

最后的判断则是看移动和旋转的值是否太小了。

太小就进行忽略。

分析

那么这个控制器为什么会造成拖拽后上方向发生变化呢,其实从上面代码的分析不难看出。

先将鼠标向上旋转一个角度

再将鼠标朝右旋转

最后再朝下拖动鼠标时

此时的相机左方向轴已经不在x轴与y轴构成的平面上了。

所以相机上方向发生了变化。

其根本原因是相机左右旋转时旋转轴是以自身上方向为旋转轴造成的。

如果要保持相机上方向一致的情况下旋转视角应该以z轴作为相机旋转的旋转轴。

这样相机怎么旋转都能保持上方向一致了。

– 欢迎点赞、关注、转发、收藏【我码玄黄】,gonghao 同名

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表