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));

使用前后对比:

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

相关推荐
快乐肚皮3 小时前
一文了解XSS攻击:分类、原理与全方位防御方案
java·前端·xss
保护我方头发丶3 小时前
ESP-wifi-蓝牙
前端·javascript·数据库
想学后端的前端工程师4 小时前
【Flutter跨平台开发实战指南:从零到上线-web技术栈】
前端·flutter
老王Bingo4 小时前
Qwen Code + Chrome DevTools MCP,让爬虫、数据采集、自动化测试效率提升 100 倍
前端·爬虫·chrome devtools
董世昌414 小时前
什么是扩展运算符?有什么使用场景?
开发语言·前端·javascript
来杯三花豆奶5 小时前
Vue 3.0 Mixins 详解:从基础到迁移的全面指南
前端·javascript·vue.js
想学后端的前端工程师5 小时前
【React性能优化实战指南:从入门到精通-web技术栈】
前端·react.js·性能优化
白兰地空瓶5 小时前
React Hooks 深度理解:useState / useEffect 如何管理副作用与内存
前端·react.js
cike_y5 小时前
JSP内置对象及作用域&双亲委派机制
java·前端·网络安全·jsp·安全开发
巴拉巴拉~~6 小时前
KMP 算法通用进度条组件:KmpProgressWidget 多维度 + 匹配进度联动 + 平滑动画
java·服务器·前端