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

使用前后对比:

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

相关推荐
小张快跑。6 分钟前
【Java企业级开发】(十一)企业级Web应用程序Servlet框架的使用(上)
java·前端·servlet
小白阿龙15 分钟前
Flex布局子元素无法垂直居中
前端
秋田君25 分钟前
前端工程化部署入门:Windows + Nginx 实现多项目独立托管与跨域解决方案
前端·windows·nginx
江城开朗的豌豆1 小时前
阿里邮件下载器使用说明
前端
半兽先生1 小时前
Web 项目地图选型指南:从 Leaflet 到 MapTalks,如何选择合适的地图引擎?
前端
hssfscv1 小时前
Javaweb 学习笔记——html+css
前端·笔记·学习
Mr.Jessy1 小时前
JavaScript高级:深浅拷贝、异常处理、防抖及节流
开发语言·前端·javascript·学习
唐叔在学习1 小时前
30s让ai编写「跳过外链中转页」的油猴脚本
前端·javascript
酸菜土狗2 小时前
🔥 纯 JS 实现 SQL 字段智能解析工具类,前端也能玩转 SQL 解析
前端