threejs系列: 几何变换(下)🏄‍♂️

这里是 threejs系列:几何变换(下):

往期回顾:

  1. # threejs系列:相机与投影 📷
  2. # threejs系列:光源与光照🪀
  3. # threejs系列:自定义几何体🎃
  4. # threejs系列:几何变换(上)🍺
  5. threejs系列: 几何变换(下)🏄‍♂️
  6. threejs系列: 矩阵推导
  7. .......

高强度持续更新,从0到1深入了解 threejs 的奥秘,喜欢的点个关注呀

几何变换

在上一篇文章中我们学习了 threejs 封装的API,确实很轻易就完成了物体的变换。但或多或少会有一点意犹未尽的感觉。

如果不使用 threejs 的API,我们能否尝试自己实现呢?

  1. 我们先创建一个工具类
js 复制代码
class Utils {
    static rotate() {
        
    }   

    static translate() {

    }

    static scale() {

    }
}
  1. 创建一个物体
js 复制代码
let mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshPhongMaterial({ color: 0xFFFFFF }))
scene.add(mesh);
  1. 实现逻辑

由于物体的变换都是通过修改几何体的顶点完成的,所以我们需要拿到物体的顶点。

位移是容易理解的,只需要每个顶点朝着相同的方向加上相同的值就完成了。

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);
}
  1. 使用写好的工具函数
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));

使用前后对比:

现在我们完美的使用数学表达式完成了几何变换。

相关推荐
Avan_菜菜3 小时前
AI 能写代码了,为什么我反而开始要求它先写文档?
前端·github·ai编程
爱勇宝7 小时前
鸿蒙生态的下半场:开发者不只要能开发,还要能赚钱
android·前端·程序员
IT_陈寒10 小时前
SpringBoot这个自动配置坑我跳了三次
前端·人工智能·后端
kyriewen10 小时前
我用 AI 一周写完了整个项目,上线第一天就崩了——这是我踩过最贵的 5 个坑
前端·javascript·ai编程
牧艺11 小时前
从零到协同:构建类飞书在线文档系统的五个技术重难点
前端·人工智能
红尘散仙11 小时前
想写一个像样的终端 App?试试把 React 的开发体验搬进 Rust TUI
前端·rust
袋鼠云数栈UED团队12 小时前
一套 Spec-First 的 AI 编程工作流
前端·人工智能
袋鼠云数栈前端12 小时前
一套 Spec-First 的 AI 编程工作流
前端·ai+
angerdream12 小时前
Android手把手编写儿童手机远程监控App之vue3 路由守卫
前端
不服老的小黑哥12 小时前
AI规范驱动编程-harness工程项目实战
前端