发布时间:2024-03-05 17:01
为了更好的理解camera的position、lookAt与up属性,文章最开始我们先来阐述three.js的坐标系转换的概念。
文章的最开始首先讨论在哪里进行点击事件的监听的问题,当鼠标触发点击事件时,event会输出点击位置相对于各个参考系所产生的坐标,在此我们只讨论常用的offsetX、offsetY以及clientX、clientY。
offsetX:设置或获取鼠标点击位置相对于触发事件对象(触发事件DOM的内部不包含border)的水平(X)距离
offsetY:设置或获取鼠标点击位置相对于触发事件对象(触发事件DOM的内部不包含border)的垂直(Y)距离
clientX:设置或获取鼠标相对于浏览器可视区域的水平坐标
clientY:设置或获取鼠标相对于浏览器可视区域的垂直坐标
如图(1)示,window中(clientX,clientY)都是相对于左上角坐标原点的距离,而(offsetX,offsetY)中触发事件的对象这个概念就很重要,是相对于当前DOM元素不包含border及其外部的content部分左上角原点坐标,如果在展示界面存在header,(clientX,clientY)还需要转换才能作为画布的坐标,所以推介选取(offsetX,offsetY)作为监听事件获得的坐标。
图(1)不同坐标数据展示
如果展示模型的画布如果是整个可视页面,监听window得到的坐标(clientX,clientY)与(offsetX,offsetY)都是一致的。但往往我们只会选择一个区域进行三维模型的展示, 这时若监听对象为window,就会在画布外触发点击事件,容易产生不必要的问题。所以此时最好把监听对象设置为存放画布的DOM元素,不仅在画布外不会触发不必要的事件,并且可以直观的获得该点相对于画布的坐标。
element.addEventListener('click',()=>{})
window.addEventListener('click',()=>{})
这里我们先抛出屏幕坐标、标准化设备坐标与世界坐标的概念。
屏幕坐标:以左上角为原点,横向为x轴,纵向向下为y轴;屏幕坐标系在three.js中为canvas画布的坐标系,如图(2)示
图(2)屏幕坐标系
标准化设备坐标(NormalizedDeviceCoordinates,NDC) :标准化设备坐标是一个横纵坐标值在-1到1的一小段空间,坐标原点位于区域正中心。如图(3)示
图(3)标准化设备坐标系
世界坐标:场景坐标原点坐标系,世界坐标是物体相对场景坐标原点的位置,如图(4)示
图(4)世界坐标系
首先我们了解如何从屏幕坐标系转化为标准化设备坐标系,最后转化为世界坐标系的过程 。
step 1:
当鼠标在canvas画布上点击时,获得屏幕坐标系(Sx,Sy),将其转化为( Nx,Ny),可得
转化为代码就是
const x = (x / Width) * 2 - 1,
const y = - (y /Height) * 2 + 1,
step 2:
将得到的设备坐标转化为三维向量;
const nVector = new THREE.Vector3((x / Width) * 2 - 1,- (y /Height) * 2 + 1,0.5)
step 3:
three.js有封装好的方法.unporject( ),将设备坐标转为世界坐标系;
const worldVector = nVector.unprojet( camera )
同上可得
step1:
将世界坐标系转化为标准坐标系
const nVector = worldVector .projet( camera )
step2:
将标准坐标系转化为屏幕坐标系,公式为
.position:Vectors
表示对象局部位置的Vector3。默认值为(0, 0, 0)
官方文档的解释很容易理解,就是相机相对于世界坐标系原点的位置,换句话说相机距离场景中心的距离。距离越近看到的物体越少越大,距离越远看到的物体越多越小。设置一个合适的位置对于观察场景内模型具有很重要的意义。
图(5)相机看向物体
object3D.lookAt ( vector:Vector3) :undefined
object3D.lookAt( x : Float, y : Float, z : Float ) :undefinedvector - 一个表示世界空间中位置的向量。
也可以使用世界空间坐标的位置分量。
旋转物体使其在世界空间中面朝一个点。这一方法不支持其父级被旋转过或者被位移过的物体。
也就是说,这个object的永远朝向 .lookAt( ) 中向量的位置,如果在创建object时使用这个属性,就会产生构建的物体总是会朝向向量的方向,图(6)示为raycaster射线射中返回的数据,借由这些数据和。lookAt()方法,我们可以完成很多有趣的功能,例如在物体表面形成数据点,或者构建垂直于当前面的线等等。
图(6)相机看向物体
而相机的这个属性可以理解为”看向“哪里,只有保证视角中出现这个对象,我们才能通过画布看到。在渲染场景时,通常都是将相机看向场景的原点,以此来保证可视界面的完整,我们也可以把相机放置在场景中移动的物体上,设置看向某个方向,借此完成动态巡检等功能。
.up:Vector3
这个属性由lookAt方法所使用,例如,来决定结果的朝向。 默认值是Object3D.DefaultUp,
即( 0, 1, 0 )
通过前面阐述的世界坐标系概念可知,这个”结果的朝向“指的是场景的坐标系的朝向,默认的朝向为Y轴向上,X轴向右,Z轴向外,那么我们设置这个值会得到什么?
a.设置Y轴向上
换句话说,就是哪个方向是向上的,设置.up为(0,1,0),就可以得到图(7)的样式,Y轴向上,X轴向右,Z轴向外。
camera.position.set(1,30,60)
camera.lookAt(0,0,0)
camera.up = new THREE.Vector3(0,1,0)
图(7)Y轴向上
b.设置Y轴向上
那么,设置.up为(1,0,0),就可以得到图(8)的样式,x轴向上,X轴向坐,Z轴向外。
camera.position.set(1,30,60)
camera.lookAt(0,0,0)
camera.up = new THREE.Vector3(1,0,0)
图(8)X轴向上
c.设置Z轴向上
设置.up为(0,0,1)时,就可以得到图(9),由图可知Z轴向外,那么为什么Z轴没有向上?通过图(10)可以知道相机的位置在Z轴正半轴,看向Z轴的负半轴,改变.up()的值,相机的位置也是在跟随着一起移动,所以得到如图所示的结果。
camera.position.set(1,30,60)
camera.lookAt(0,0,0)
camera.up = new THREE.Vector3(1,0,0)
图(9)Z轴向上