THREE.Plane 在 threejs
中用來表示數學上的平面
數學中的平面方程式
a, b, c
代表平面的法向量,d
是一個常數值
1 | ax + by + cz + d = 0; |
創建平面
以下程式碼創建了一個 y - 1 = 0
的平面,法向量為 [0, 1, 0]
,常數值為 -1
1 | const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0).normalize(), -1); |
這裡需要特別注意的是傳入法向量時需要將其轉換為單位向量,[0, 10, 0]
跟 [0, 1, 0]
在向量的定義上是一樣的,都是指向正 x 軸方向,但 threejs
要求在牽涉到法向量時都必須是單位向量,否則在某些運算上會錯誤,所以以上程式碼才刻意加了 .normalize()
Plane 的方法
- distanceToPoint(point: Vector3): Float
計算傳入的 point
與平面的距離
1 | const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), -1); |
這裡就可以看出為什麼一開始傳入法向量要是單位向量,以下面的例子來看:
1 | const plane = new THREE.Plane(new THREE.Vector3(0, 10, 0), -1); |
[0, 1, 0]
與 [0, 10, 0]
在法向量的定義上是一樣的,所以計算出來的點與平面的距離應該要一樣,但這兩個寫法的結果卻完全不一樣,原因可以從 threejs
的 distanceToPoint 來查看
1 | distanceToPoint(point) { |
從 threejs
原始碼來看,假設 point
座標為 (x0, y0, z0)
,計算 distanceToPoint
的數學式為:
$$ ax_0 + by_0 + cz_0 + d $$
但實際用數學計算某個點與平面的距離公式是:
$$ \frac{\lvert ax_0 + by_0 + cz_0 + d \rvert}{\sqrt{a^2+b^2+c^2}} $$
可以看出來差異就在分母的 $ \sqrt{a^2+b^2+c^2} $,而這個東西就是法向量的長度,當法向量為單位向量時分母會等於 1
,如此一來使用 threejs
的 distanceToPoint
才會與數學計算的結果一致,這也就是為什麼 threejs
中的法向量都需要先自行轉換為單位向量
Refs.
點到平面的距離公式推導
Use unit norm when finding plane distanceToPoint
- projectPoint(point:Vector3, target:Vector3): Vector3
計算空間中的某個點 point
投影到平面上的座標
point
- 空間中的某個點 $(x_0, y_0, z_0)$target
- 投影到平面的座標回傳值
- 投影到平面的座標
1 | const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0), -1); |
原始碼
1 | projectPoint( point, target ) { |
數學推導
$ (x, y, z) = (x_0 - at, y_0 - bt, z_0 - ct) $
$ ax + by + cz + d = 0 $
$ a(x_0 - at) + b(y_0 - bt) + c(z_0 - ct) + d = 0 $
$ ax_0 + by_0 + cz_0 - a^2t - b^2t - z^2t + d = 0 $
=>
$$ t = \frac{ax_0 + by_0 + cz_0 + d}{a^2+b^2+c^2} = ax_0 + by_0 + cz_0 + d = distanceToPoint(point) $$
$$ (x, y, z) = (x_0 - at, y_0 - bt, z_0 - ct) = (x_0, y_0, z_0) + (a, b, c) \cdot -distanceToPoint(point) $$
Refs.
- coplanarPoint(target: Vector3): Vector3
計算沿著原點方向投影到平面的共面點
target
- 沿著原點方向投影到平面的共面點 $(x, y, z)$
coplanarPoint
的意思是共面點,代表這個點位於平面上,coplanarPoint
的概念跟 projectPoint
很像,差別在 coplanarPoint
投影到平面上的點是沿著原點的方向,而 projectPoint
是沿著平面法向量的方向
1 | const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0).normalize(), -1); |
原始碼
1 | coplanarPoint(target) { |
數學推導
$ (x, y, z) = (at, bt, ct) $
$ ax + by + cz + d = 0 $
$ t \times (a^2+b^2+c^2) + d = 0 $
$ t = -d $
$ (x, y, z) = (a, b, c) \times -d $
- setFromNormalAndCoplanarPoint(normal: Vector3, point: Vector3 )
這個方法藉由提供平面的法向量及平面上某點的座標創建出平面
normal
- 平面的法向量 $(a, b, c)$point
- 平面上某個點的座標 $(x, y, z)$
1 | const plane = new THREE.Plane(new THREE.Vector3(0, 1, 0).normalize(), -1); |
原始碼
1 | setFromNormalAndCoplanarPoint(normal, point) { |
數學推導
$ (a, b, c) \cdot (x, y, z) + d = 0 $
$ d = - (x, y, z) \cdot (a, b, c) $
DEMO
版本
- threejs r159