Three.js Object3D的移动、旋转、缩放及矩阵转化

3/24/2023 three.js

# 1. Transition、Scale、Rotate

在 three.js 中,空间分为世界空间对象空间scene的直接子对象相对于世界空间定位,而对象的子对象相对于对象空间定位

image.png

所有的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

初始为单位矩阵IT代表TransitionS代表ScaleR代表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
    我想,
    在这个世界上,
    虽然没有最美好的相遇,
    但却应该有为了相遇或重逢,
    所做的最美好的努力。
    红莲华
    x
    loading...