Three.js Object3D的移动、旋转、缩放及矩阵转化
NOxONE 3/24/2023 three.js
# 1. Transition、Scale、Rotate
在 three.js 中,空间分为世界空间
和对象空间
,scene
的直接子对象相对于世界空间
定位,而对象的子对象相对于对象空间
定位
所有的Object3D
基于空间里的笛卡尔坐标系移动、旋转和缩放
class Object3D {
constructor() {
this.position = {
// transition
x: 0,
y: 0,
z: 0,
set(x, y, z) {
this.x = x
this.y = y
this.z = z
},
}
this.scale = {
// scale
x: 0,
y: 0,
z: 0,
set(x, y, z) {
this.x = x
this.y = y
this.z = z
},
}
this.rotate = {
// rotate
x: 0,
y: 0,
z: 0, // rad
set(x, y, z) {
this.x = x
this.y = y
this.z = z
},
}
// ...
}
}
// 通过Vector3改变transtion、scale
let o = new Object3D()
o.postion = new Vector3(1, 1, 1) // 等价于:o.postion.set(1,1,1)
o.scale = new Vector3(2, 2, 2) // 等价于:o.scale.set(2,2,2)
// 通过Euler改变rotate,通过MathUtils.degToRad方法将角度deg转为rad弧度
import { MathUtils } from 'three'
let radX = MathUtils.degToRad(90) // 90deg --> Math.PI * (90 / 180) --> Math.PI / 2
let radY = MathUtils.degToRad(-90)
let radZ = MathUtils.degToRad(90)
o.rotate = new Euler(radX, radY, radZ) // 等价于:o.rotate.set(radX, radY, radZ)
# 2. 转换矩阵
对于计算机处理向量
、欧拉角
的效率并不高,更推荐将平移、旋转、缩放转换成一个 4 维矩阵即Matrix4
初始为单位矩阵I
,T
代表Transition
,S
代表Scale
,R
代表Rotate
o.postion.set(Tx, Ty, Tz)
o.scale.set(Sx, Sy, Sz)
o.updateMatrix() // 更新Matrix
// 合并TS,先不考虑R
let TSMatix = [
[Sx, 0, 0, Tx],
[0, Sy, 0, Ty],
[0, 0, Sz, Tz],
[0, 0, 0, 1],
]
旋转比较特殊
let rad = MathUtils.degToRad(30) // Math.PI / 6
let s0 = Math.sin(rad)
let c0 = Math.cos(rad)
o.rotate.x = rad
let RxMatix = [
[1, 0, 0, 0],
[0, c0, s0, 0],
[0, -s0, c0, 0],
[0, 0, 0, 1],
]
o.rotate.y = rad
let RyMatix = [
[c0, 0, s0, 0],
[0, 1, 0, 0],
[-s0, 0, c0, 0],
[0, 0, 0, 1],
]
o.rotate.z = rad
let RzMatix = [
[c0, -s0, 0, 0],
[s0, c0, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
]
合并TSR
,需要对矩阵做相乘
let { cos, sin } = Math
let rad = MathUtils.degToRad(0) // Math.PI / 6
let c0 = cos(rad)
let s0 = sin(rad)
o.rotate.x = rad
o.rotate.y = rad
o.rotate.z = rad
o.postion.set(1, 2, 3)
o.scale.set(2, 2, 2)
o.updateMatix()
// 合并TSR
let TSRMatix = TSMatix * RxMatix * RyMatix * RzMatix // 自己算,我也不会~
# 3. 世界空间矩阵和对象空间矩阵的转化
const scene = new Scene()
const meshA = new Mesh()
const meshB = new Mesh()
scene.add(meshA)
meshA.add(meshB)
// meshA矩阵变换
let matixA = new Matix4()
matixA.set(1, 0, 0, 5, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
meshA.matix = matixA // 等价于 meshA.position.set(5,0,0)
// meshB矩阵变换
let matixB = new Matix4()
matixB.set(1, 0, 0, 2, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
meshB.matix = matixB // 等价于 meshA.position.set(2,0,0)
// meshA.matrix和meshA.matrixWorld相同都为 matixA
meshA.updateMatrix()
meshA.updateMatrixWorld()
// meshB.matrix为matrixB
meshB.updateMatrix()
// meshB.matrixWorld为 matixA + matrixB
meshB.updateMatrixWorld()
// 等价于以下代码
let matrixWorldB = new Matrix4()
matrixWorldB.set(1, 0, 0, 7, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
meshB.matixWorld = matrixWorldB