Three.js 数学工具:构建精确3D世界的基石

news2025/1/15 3:39:18

文章目录

    • 前言
    • 一、向量(Vectors)
    • 二、矩阵(Matrices)
    • 三、四元数(Quaternions)
    • 四、欧拉角(Euler Angles)
    • 五、颜色(Colors)
    • 六、几何体生成器(Geometry Generators)
    • 七、随机数生成(Random Number Generation)
    • 八、时间和动画(Time and Animation)
    • 九、光线追踪与碰撞检测(Ray Tracing and Collision Detection)
    • 十、曲线与路径(Curves and Paths)
    • 十一、数学常量与实用函数(Math Constants and Utility Functions)
    • 结语


前言

在创建复杂的3D图形和动画时,数学扮演着不可或缺的角色。Three.js 提供了一套强大且易于使用的数学工具库,这些工具帮助开发者处理从基本的几何变换到高级物理模拟的各种任务。本文将深入探讨 Three.js 中提供的数学工具,并通过具体的代码示例来说明如何利用它们为你的项目增添精度与灵活性。


一、向量(Vectors)

向量是表示位置、方向或速度等概念的基础数据结构。Three.js 支持多种类型的向量,包括 Vector2, Vector3Vector4,分别用于二维、三维和四维空间中的计算。

创建和操作向量

// 创建一个三维向量
const vector = new THREE.Vector3(1, 0, 0);

// 执行基本运算
vector.add(new THREE.Vector3(0, 1, 0)); // 加法
vector.sub(new THREE.Vector3(0, 1, 0)); // 减法
vector.multiplyScalar(2);               // 标量乘法
vector.normalize();                     // 归一化

// 计算两个向量之间的角度
const angle = vector.angleTo(new THREE.Vector3(0, 1, 0));

// 计算点积和叉积
const dotProduct = vector.dot(new THREE.Vector3(0, 1, 0));
const crossProduct = vector.cross(new THREE.Vector3(0, 1, 0));

// 应用到对象的位置或旋转
object.position.copy(vector);
object.quaternion.setFromUnitVectors(object.up, vector);

二、矩阵(Matrices)

矩阵用于描述物体的空间变换,如平移、旋转和缩放。Three.js 提供了 Matrix4 类来进行这些操作,并支持矩阵之间的乘法以组合多个变换。

应用矩阵变换

// 创建一个四元数并应用旋转
const quaternion = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 4);
const matrix = new THREE.Matrix4();
matrix.makeRotationFromQuaternion(quaternion);

// 将矩阵应用于对象
object.applyMatrix4(matrix);

// 组合平移、旋转和缩放
const translateMatrix = new THREE.Matrix4().makeTranslation(1, 0, 0);
const rotationMatrix = new THREE.Matrix4().makeRotationX(Math.PI / 4);
const scaleMatrix = new THREE.Matrix4().makeScale(2, 1, 1);

// 组合所有变换
const combinedMatrix = new THREE.Matrix4();
combinedMatrix.multiplyMatrices(translateMatrix, rotationMatrix);
combinedMatrix.multiply(scaleMatrix);

// 应用组合后的矩阵
object.applyMatrix4(combinedMatrix);

三、四元数(Quaternions)

四元数是一种高效的旋转表示方法,避免了万向锁问题。Three.js 的 Quaternion 类提供了简单易用的接口来管理旋转。

使用四元数进行旋转

// 创建一个四元数并设置旋转角度
const quaternion = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 4);

// 应用旋转到对象
object.quaternion.copy(quaternion);

// 插值两个四元数之间的旋转
const targetQuaternion = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2);
quaternion.slerp(targetQuaternion, 0.5); // 线性插值

// 更新对象的旋转
object.quaternion.copy(quaternion);

四、欧拉角(Euler Angles)

欧拉角提供了一种直观的方式来指定旋转顺序,尽管它容易导致万向锁的问题。Three.js 的 Euler 类允许你定义绕 X、Y 和 Z 轴的旋转角度。

使用欧拉角进行旋转

// 创建一个欧拉角实例
const euler = new THREE.Euler(Math.PI / 4, 0, 0, 'XYZ');

// 应用到对象的旋转属性
object.rotation.setFromEuler(euler);

// 修改欧拉角的值
euler.x += Math.PI / 8;
object.rotation.setFromEuler(euler);

// 注意:避免直接修改 rotation 属性,因为这可能导致不一致的状态

五、颜色(Colors)

颜色不仅是视觉效果的重要组成部分,而且在材质和光照中也起着关键作用。Three.js 的 Color 类简化了颜色的创建和操作。

创建和操作颜色

// 创建一个颜色实例
const color = new THREE.Color(0xff0000); // 红色

// 修改颜色值
color.setRGB(0, 1, 0); // 变为绿色
color.setHSL(0.5, 1, 0.5); // 使用 HSL 设置颜色

// 应用到材质
material.color.copy(color);

// 获取颜色的十六进制表示
console.log(`颜色的十六进制表示: ${color.getHexString()}`);

// 设置颜色的透明度
material.opacity = 0.5;
material.transparent = true; // 必须开启透明度

六、几何体生成器(Geometry Generators)

Three.js 提供了一系列内置的几何体生成器,如 BoxGeometry, SphereGeometry 等,用于快速创建常见形状。此外,还可以通过自定义顶点和面来构建复杂的几何体。

创建几何体

// 创建一个立方体几何体
const geometry = new THREE.BoxGeometry(1, 1, 1);

// 创建一个球体几何体
const sphereGeometry = new THREE.SphereGeometry(0.5, 32, 32);

// 自定义几何体
const customGeometry = new THREE.Geometry();
customGeometry.vertices.push(
    new THREE.Vector3(-1, -1, 0),
    new THREE.Vector3(1, -1, 0),
    new THREE.Vector3(0, 1, 0)
);
customGeometry.faces.push(new THREE.Face3(0, 1, 2));

// 创建网格并添加到场景
const mesh = new THREE.Mesh(customGeometry, material);
scene.add(mesh);

七、随机数生成(Random Number Generation)

虽然 Three.js 没有直接提供随机数生成函数,但可以结合 JavaScript 的 Math.random() 来实现这一功能,这对于创建程序化内容非常有用。

生成随机数

// 生成介于 min 和 max 之间的随机浮点数
function getRandomFloat(min, max) {
    return (max - min) * Math.random() + min;
}

// 示例:生成随机位置的球体
for (let i = 0; i < 100; i++) {
    const sphere = new THREE.Mesh(
        new THREE.SphereGeometry(0.1, 16, 16),
        new THREE.MeshBasicMaterial({ color: 0xffffff * Math.random() })
    );
    sphere.position.set(
        getRandomFloat(-5, 5),
        getRandomFloat(-5, 5),
        getRandomFloat(-5, 5)
    );
    scene.add(sphere);
}

八、时间和动画(Time and Animation)

时间管理对于创建流畅的动画至关重要。Three.js 提供了 Clock 类来跟踪时间,并结合 requestAnimationFrame 实现平滑的动画更新。

管理时间和动画

// 创建一个时钟实例
const clock = new THREE.Clock();

// 在动画循环中获取经过的时间
function animate() {
    requestAnimationFrame(animate);

    const delta = clock.getDelta(); // 获取上一帧到当前帧的时间差
    object.rotation.x += delta * 0.1; // 根据时间调整旋转速度

    renderer.render(scene, camera);
}
animate();

// 使用 Tween.js 进行补间动画
import { Tween } from '@tweenjs/tween.js';

new Tween(object.position)
    .to({ x: 5 }, 1000) // 目标位置和持续时间
    .start();

九、光线追踪与碰撞检测(Ray Tracing and Collision Detection)

光线追踪用于模拟光的行为,而碰撞检测则用于确定物体是否相交。Three.js 提供了 Raycaster 类来实现这两种功能。

// 创建 Raycaster 和鼠标位置变量
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();

// 监听鼠标点击事件
window.addEventListener('click', (event) => {
    // 将鼠标位置标准化为设备坐标 (-1 到 +1)
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

    // 更新 Raycaster 的方向向量
    raycaster.setFromCamera(mouse, camera);

    // 检查交点
    const intersects = raycaster.intersectObjects(scene.children);
    if (intersects.length > 0) {
        console.log('点击的对象:', intersects[0].object);
    }
});

// 碰撞检测
function checkCollisions(objectA, objectB) {
    const distance = objectA.position.distanceTo(objectB.position);
    return distance < (objectA.geometry.boundingSphere.radius + objectB.geometry.boundingSphere.radius);
}

十、曲线与路径(Curves and Paths)

曲线和路径用于定义物体的运动轨迹或其他复杂形状。Three.js 提供了多种曲线类型,如 LineCurve3, CubicBezierCurve3SplineCurve

创建和使用曲线

// 创建一条贝塞尔曲线
const curve = new THREE.CubicBezierCurve3(
    new THREE.Vector3(-1, 0, 0),
    new THREE.Vector3(-0.5, 1, 0),
    new THREE.Vector3(0.5, 1, 0),
    new THREE.Vector3(1, 0, 0)
);

// 获取曲线上某一点的位置
const point = curve.getPoint(0.5);

// 创建路径并添加到场景
const path = new THREE.Path(curve.getPoints(50));
const geometry = path.createPointsGeometry();
const material = new THREE.LineBasicMaterial({ color: 0x0000ff });
const line = new THREE.Line(geometry, material);
scene.add(line);

十一、数学常量与实用函数(Math Constants and Utility Functions)

Three.js 提供了一些常用的数学常量和实用函数,如 MathUtils,方便进行各种数学运算。

使用数学常量和实用函数

// 使用 PI 常量
const pi = Math.PI;

// 使用 MathUtils 中的方法
const radians = THREE.MathUtils.degToRad(90); // 将度数转换为弧度
const degrees = THREE.MathUtils.radToDeg(radians); // 将弧度转换为度数

// 计算两点间的距离
const distance = THREE.MathUtils.euclideanModulo(pointA.x - pointB.x, 10);

结语

Three.js 的数学工具不仅限于上述几种方式,还包括更多高级特性,如光线追踪、碰撞检测等。掌握这些数学工具,可以帮助你在创建3D内容时提供更加精确和灵活的操作。无论你是希望构建一个教育性的演示文稿,还是开发一款复杂的游戏,Three.js 的数学能力都能为你提供强有力的支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2276779.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录算法【Day20】

Day20 二叉搜索树 235. 二叉搜索树的最近公共祖先 理解只要当前节点的值在p和q节点的值的中间&#xff0c;那这个值就是最近的公共祖先&#xff0c;绝对不是次近的&#xff0c;这个题就好做了。 递归法 二叉搜索树本身是有序的&#xff0c;所以不涉及到前中后序的遍历 cl…

【SpringBoot】@Value 没有注入预期的值

问题复现 在装配对象成员属性时&#xff0c;我们常常会使用 Autowired 来装配。但是&#xff0c;有时候我们也使用 Value 进行装配。不过这两种注解使用风格不同&#xff0c;使用 Autowired 一般都不会设置属性值&#xff0c;而 Value 必须指定一个字符串值&#xff0c;因为其…

车联网安全 -- 数字证书到底证明了什么?

在车联网安全--TLS握手过程详解里面&#xff0c;我们了解到握手时&#xff0c;Server会向Client发送Server Certificate&#xff0c;用于证明自己的身份合法&#xff0c;为什么会有这一步呢&#xff1f; 我们回顾一下数字签名的过程&#xff1a; Bob将使用自己的公钥对“Hello…

Elasticsarch:使用全文搜索在 ES|QL 中进行过滤 - 8.17

8.17 在 ES|QL 中引入了 match 和 qstr 函数&#xff0c;可用于执行全文过滤。本文介绍了它们的作用、使用方法、与现有文本过滤方法的区别、当前的限制以及未来的改进。 ES|QL 现在包含全文函数&#xff0c;可用于使用文本查询过滤数据。我们将回顾可用的文本过滤方法&#xf…

【HTML+CSS+JS+VUE】web前端教程-31-css3新特性

圆角 div{width: 100px;height: 100px;background-color: saddlebrown;border-radius: 5px;}阴影 div{width: 200px;height: 100px;background-color: saddlebrown;margin: 0 auto;box-shadow: 10px 10px 20px rgba(0, 0, 0, 0.5);}

Spring Boot 项目自定义加解密实现配置文件的加密

在Spring Boot项目中&#xff0c; 可以结合Jasypt 快速实现对配置文件中的部分属性进行加密。 完整的介绍参照&#xff1a; Spring Boot Jasypt 实现application.yml 属性加密的快速示例 但是作为一个技术强迫症&#xff0c;总是想着从底层开始实现属性的加解密&#xff0c;…

若依前后端分离项目部署(使用docker)

文章目录 一、搭建后端1.1 搭建流程&#xff1a;1.2 后端零件:1.2.1 mysql容器创建&#xff1a;1.2.2 redis容器创建&#xff1a;1.2.3 Dockerfile内容&#xff1a;1.2.4 构建项目镜像&#xff1a;1.2.5 创建后端容器&#xff1a; 二、前端搭建&#xff1a;2.1 搭建流程&#x…

Vue2+OpenLayers使用Overlay实现点击获取当前经纬度信息(提供Gitee源码)

目录 一、案例截图 二、安装OpenLayers库 三、代码实现 关键参数&#xff1a; 实现思路&#xff1a; 核心代码&#xff1a; 完整代码&#xff1a; 四、Gitee源码 一、案例截图 二、安装OpenLayers库 npm install ol 三、代码实现 覆盖物&#xff08;Overlay&#xf…

Oracle 终止正在执行的SQL

目录 一. 背景二. 操作简介三. 投入数据四. 效果展示 一. 背景 项目中要求进行性能测试&#xff0c;需要向指定的表中投入几百万条数据。 在数据投入的过程中发现投入的数据不对&#xff0c;需要紧急停止SQL的执行。 二. 操作简介 &#x1f449;需要DBA权限&#x1f448; ⏹…

Oopsie【hack the box】

Oopsie 解题流程 文件上传 首先开启机器后&#xff0c;我们先使用 nmap -sC -SV来扫描一下IP地址&#xff1a; -sC&#xff1a;使用 Nmap 的默认脚本扫描&#xff08;通常是 NSE 脚本&#xff0c;Nmap Scripting Engine&#xff09;。这个选项会自动执行一系列常见的脚本&am…

V少JS基础班之第四弹

一、 前言 第四弹内容是操作符。 本章结束。第一个月的内容就完成了&#xff0c; 是一个节点。 下个月我们就要开始函数的学习了。 我们学习完函数之后。很多概念就可以跟大家补充说明了。 OK&#xff0c;那我们就开始本周的操作符学习 本系列为一周一更&#xff0c;计划历时6…

【STM32-学习笔记-7-】USART串口通信

文章目录 USART串口通信Ⅰ、硬件电路Ⅱ、常见的电平标准Ⅲ、串口参数及时序Ⅳ、STM32的USART简介数据帧起始位侦测数据采样波特率发生器 Ⅴ、USART函数介绍Ⅵ、USART_InitTypeDef结构体参数1、USART_BaudRate2、USART_WordLength3、USART_StopBits4、USART_Parity5、USART_Mode…

Docker 安装开源的IT资产管理系统Snipe-IT

一、安装 1、创建docker-compose.yaml version: 3services:snipeit:container_name: snipeitimage: snipe/snipe-it:v6.1.2restart: alwaysports:- "8000:80"volumes:- ./logs:/var/www/html/storage/logsdepends_on:- mysqlenv_file:- .env.dockernetworks:- snip…

达梦8-DMSQL程序设计学习笔记1-DMSQL程序简介

1、DMSQL程序简介 DMSQL程序是达梦数据库对标准SQL语言的扩展&#xff0c;是一种过程化SQL语言。在DMSQL程序中&#xff0c;包括一整套数据类型、条件结构、循环结构和异常处理结构等&#xff0c;DMSQL程序中可以执行SQL语句&#xff0c;SQL语句中也可以使用DMSQL函数。 DMSQ…

NLP中常见的分词算法(BPE、WordPiece、Unigram、SentencePiece)

文章目录 一、基本概念二、传统分词方法2.1 古典分词方法2.2 拆分为单个字符 三、基于子词的分词方法&#xff08;Subword Tokenization&#xff09;3.1 主要思想3.2 主流的 Subword 算法3.3 Subword 与 传统分词方法的比较 四、Byte Pair Encoding (BPE)4.1 主要思想4.2 算法过…

第三十六章 Spring之假如让你来写MVC——拦截器篇

Spring源码阅读目录 第一部分——IOC篇 第一章 Spring之最熟悉的陌生人——IOC 第二章 Spring之假如让你来写IOC容器——加载资源篇 第三章 Spring之假如让你来写IOC容器——解析配置文件篇 第四章 Spring之假如让你来写IOC容器——XML配置文件篇 第五章 Spring之假如让你来写…

PyTorch 深度学习框架快速入门 (小土堆)

PyTorch 深度学习框架快速入门 深度学习框架常用模块数据集存取图片数据处理库 —— PILOS 模块实例 Tensorboard 记录机器学习的过程Transform 进行图像变换数据集的下载DataLoaderModule 自定义网络前向传播卷积层卷积简单应用 最大池化非线性层线性层 简单的整合基于现有网络…

FPGA的 基本结构(Xilinx 公司Virtex-II 系列FPGA )

以Xilinx 公司Virtex-II 系列FPGA 为例&#xff0c;其基本结构由下图所示。它是主要由两大部分组成&#xff1a;可编程输入/输出&#xff08;Programmable I/Os&#xff09;部分和内部可配置&#xff08;Configurable Logic&#xff09;部分。 可编程输入/输出&#xff08;I/Os…

【Elasticsearch】批量操作:优化性能

🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程,高并发设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s,热衷于探…

C++、Haskell 和 Rust 三种语言实现 Faster Suffix Sort 算法的比较

对 C、Haskell 和 Rust 三种语言实现 Faster Suffix Sort 算法的比较&#xff1a; 1. 编程效率 C&#xff1a; 优点&#xff1a;C 提供了丰富的标准库&#xff0c;如 std::sort&#xff0c;可以方便地结合自定义比较函数对后缀数组进行排序。使用 Lambda 表达式可以简洁地实现…