要理解坐标系间的转换过程,需要提前了解:
- ThreeJS 中的几种坐标系
- 屏幕坐标系和标准设备坐标系
不想看链接中的内容这边也有不规范的简述:
物体的坐标转换过程大致为:局部坐标 -> 世界坐标 -> 观察空间坐标 -> 裁剪空间坐标 -> 屏幕空间坐标
我们将 观察空间坐标系 和 裁剪空间坐标系 之间的转换统一处理,最终得到 标准设备坐标系
因此坐标转换过程就变成了:局部坐标 -> 世界坐标 -> 标准设备坐标 -> 屏幕空间坐标
原本世界坐标转换到观察空间坐标需要乘上视图矩阵 CameraMatrixWorldInverse(ViewMatrix)
随后,观察空间坐标转换到裁剪空间坐标需要乘上相机投影矩阵:ProjectMatrix
在 ThreeJS 中有一个方法 Vector3.project(camera)
综合了这两步:
project( camera ) {
return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );
}
屏幕坐标系和标准设备坐标
ThreeJS 是使用了 canvas
画布绘制图形的,因此屏幕坐标系就是 canvas
中的坐标系,也就是左上角是坐标原点:
![image-20210117192758975](https://i-blog.csdnimg.cn/blog_migrate/476f48ff5acecb6ea46d58a8fc85aedf.png)
在 ThreeJS 中,一个物体可看作一个 Mesh
,Mesh
的坐标是用一个 Vector3
来表示的,Vector3
中包含了 x
、y
、z
坐标。
空间坐标系是三维的,其原点默认在屏幕中心,且 x y z
的范围是 [-1,1]
,因此其 x
、y
轴在屏幕坐标系中的表示就是:
![image-20210117193755299](https://i-blog.csdnimg.cn/blog_migrate/f1ce7660b5e280660296ab42ec35ba35.png)
屏幕坐标转世界坐标
屏幕坐标转空间坐标需要经过两个步骤:屏幕坐标 -> 标准设备坐标 -> 世界坐标
ThreeJS 中,画布一般是全屏的,因此画布的宽高 w,h
就是:window.innerWidth
和 window.innerHeight
,所以 Three 的空间坐标系中点 (cx, cy)
在屏幕坐标系中就是:(w / 2,h / 2)
。
(根据情况,有时候宽高会是 canvas.offsetWidth
和 canvas.offsetHeight
)
假设 canvas
中有一点 (x,y)
,这个点在空间坐标系中为 (x1,y1)
,那么这个转换公式是:
x 1 = ( x / w ) ∗ 2 − 1 x1 = (x / w) * 2 - 1 x1=(x/w)∗2−1
y 1 = − ( y / h ) ∗ 2 + 1 y1 = -(y / h) * 2 + 1 y1=−(y/h)∗2+1
公式推导过程如下:
-
首先,我们知道了空间坐标系中点在屏幕坐标系中的表示: c x = w / 2 cx = w / 2 cx=w/2, c y = h / 2 cy = h / 2 cy=h/2
-
那么,屏幕坐标系中的点 ( x