这里是 threejs系列:几何变换(下):
往期回顾:
- # threejs系列:相机与投影 📷
- # threejs系列:光源与光照🪀
- # threejs系列:自定义几何体🎃
- # threejs系列:几何变换(上)🍺
- threejs系列: 几何变换(下)🏄♂️
- threejs系列: 矩阵推导
- .......
高强度持续更新,从0到1深入了解 threejs 的奥秘,喜欢的点个关注呀
几何变换
在上一篇文章中我们学习了 threejs 封装的API,确实很轻易就完成了物体的变换。但或多或少会有一点意犹未尽的感觉。
如果不使用 threejs 的API,我们能否尝试自己实现呢?
- 我们先创建一个工具类
js
class Utils {
static rotate() {
}
static translate() {
}
static scale() {
}
}
- 创建一个物体
js
let mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshPhongMaterial({ color: 0xFFFFFF }))
scene.add(mesh);
- 实现逻辑
由于物体的变换都是通过修改几何体的顶点完成的,所以我们需要拿到物体的顶点。
位移是容易理解的,只需要每个顶点朝着相同的方向加上相同的值就完成了。
js
// 位移
translate(mesh, vector) {
let points = mesh.geometry.attributes.position.array;
points = points.map((v, index) => {
let isX = index % 3 == 0;
let isY = index % 3 == 1;
return isX ? v + vector.x : isY ? v + vector.y : v + vector.z
})
mesh.geometry.setAttribute('position', new THREE.Float32BufferAttribute(points, 3));
}
其次是缩放,也很好理解,只需要每个顶点每个方向乘以相同的值。
js
// 缩放
static scale(mesh, vector) {
let points = mesh.geometry.attributes.position.array;
points = points.map((v, index) => {
let isX = index % 3 == 0;
let isY = index % 3 == 1;
return isX ? v * vector.x : isY ? v * vector.y : v * vector.z
})
mesh.geometry.setAttribute('position', new THREE.Float32BufferAttribute(points, 3));
}
最后是旋转,旋转稍微需要思考一下。
在阅读前面的文章中我们知道 2D 旋转公式是:
js
x1 = x * Math.cos(angle) - y * Math.sin(angle);
y1 = x * Math.sin(angle) + y * Math.cos(angle);
又因为当我们绕着X方向旋转时,每个顶点的X轴位置时不变的,Y、Z同理,所以我们可以带入2D平面公式求旋转后的顶点坐标:
js
// 旋转
static __r(mesh, direct, radian) {
let points = mesh.geometry.attributes.position.array;
points = points.map((v, index) => {
let isX = index % 3 == 0;
let isY = index % 3 == 1;
let isZ = index % 3 == 2;
if (direct == 'X') {
if (isY) {
v = v * Math.cos(radian) - points[index + 1] * Math.sin(radian);
}
if (isZ) {
v = points[index - 1] * Math.sin(radian) + v * Math.cos(radian);
}
}
if (direct == 'Y') {
if (isX) {
v = v * Math.cos(radian) - points[index + 2] * Math.sin(radian);
}
if (isZ) {
v = points[index - 2] * Math.sin(radian) + v * Math.cos(radian);
}
}
if (direct == 'Z') {
if (isX) {
v = v * Math.cos(radian) - points[index + 1] * Math.sin(radian);
}
if (isY) {
v = points[index - 1] * Math.sin(radian) + v * Math.cos(radian);
}
}
return v;
})
mesh.geometry.setAttribute('position', new THREE.Float32BufferAttribute(points, 3));
}
rotate(mesh, vector) {
vector.x && this.__r(mesh, "X", vector.x);
vector.y && this.__r(mesh, "X", vector.y);
vector.z && this.__r(mesh, "Z", vector.z);
}
- 使用写好的工具函数
javascript
Utils.scale(mesh, new THREE.Vector3(1, 1, 2))
Utils.translate(mesh, new THREE.Vector3(1, 1, 1));
Utils.rotate(mesh, new THREE.Euler(Math.PI / 3, Math.PI / 3, Math.PI / 3));
使用前后对比:
现在我们完美的使用数学表达式完成了几何变换。