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

使用前后对比:

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

相关推荐
abigale032 小时前
webpack+vite前端构建工具 -11实战中的配置技巧
前端·webpack·node.js
专注API从业者2 小时前
构建淘宝评论监控系统:API 接口开发与实时数据采集教程
大数据·前端·数据库·oracle
Joker`s smile2 小时前
Chrome安装老版本、不同版本,自制便携版本用于前端调试
前端·chrome
weixin_416639972 小时前
爬虫工程师Chrome开发者工具简单介绍
前端·chrome·爬虫
我是如子啊2 小时前
【解决“此扩展可能损坏”】Edge浏览器(chrome系列通杀))扩展损坏?一招保留数据快速修复
前端·chrome·edge
灵性花火2 小时前
Qt的前端和后端过于耦合(0/7)
开发语言·前端·qt
孤水寒月6 小时前
基于HTML的悬窗可拖动记事本
前端·css·html
祝余呀6 小时前
html初学者第一天
前端·html
耶啵奶膘9 小时前
uniapp+firstUI——上传视频组件fui-upload-video
前端·javascript·uni-app
视频砖家9 小时前
移动端Html5播放器按钮变小的问题解决方法
前端·javascript·viewport功能