从零开始学习three.js(21):一文详解three.js中的矩阵Matrix和向量Vector
一、三维世界的数学基石
在Three.js的三维世界里,所有视觉效果的实现都建立在严密的数学基础之上。其中向量(Vector) 和矩阵(Matrix) 是最核心的数学工具,它们就像构建数字宇宙的原子与分子,支撑着物体的移动、旋转、缩放以及复杂的空间变换。本文一文详解向量(Vector) 和矩阵(Matrix)。
1.1 向量:三维空间的基本元素
向量是描述空间方向和位置的数学实体,在Three.js中主要使用以下三种向量类型:
// 三维向量(最常用)
const position = new THREE.Vector3(1, 2, 3);// 二维向量(用于UV映射)
const uvCoord = new THREE.Vector2(0.5, 0.5);// 四维向量(颜色RGBA或特殊计算)
const color = new THREE.Vector4(1, 0, 0, 0.5);
核心操作示例:
// 向量加法(物体位移)
const v1 = new THREE.Vector3(1, 2, 3);
const v2 = new THREE.Vector3(4, 5, 6);
v1.add(v2); // (5,7,9)// 点积计算(光照计算)
const lightDir = new THREE.Vector3(0, 1, 0).normalize();
const normal = new THREE.Vector3(0, 0, 1);
const dotProduct = lightDir.dot(normal); // 0// 叉乘应用(计算法线)
const tangent = new THREE.Vector3(1, 0, 0);
const bitangent = new THREE.Vector3(0, 1, 0);
const normal = tangent.cross(bitangent); // (0,0,1)
1.2 矩阵:空间变换
Three.js中的矩阵主要用于描述空间变换关系,以下是关键矩阵类型:
矩阵类型 | 维度 | 应用场景 |
---|---|---|
Matrix3 | 3x3 | UV变换、法线矩阵 |
Matrix4 | 4x4 | 模型视图投影矩阵(核心) |
Matrix4数组 | - | 实例化渲染 |
二、矩阵运算的奥秘
2.1 基础矩阵操作
// 创建单位矩阵(所有矩阵变换的起点)
const identityMat = new THREE.Matrix4().identity();// 矩阵相乘(变换组合)
const rotateMat = new THREE.Matrix4().makeRotationX(Math.PI/2);
const translateMat = new THREE.Matrix4().makeTranslation(0, 5, 0);
const finalMat = translateMat.multiply(rotateMat); // 注意顺序!// 矩阵求逆(坐标系转换)
const viewMatrix = camera.matrixWorldInverse;
2.2 矩阵分解技巧
const matrix = new THREE.Matrix4();
const position = new THREE.Vector3();
const quaternion = new THREE.Quaternion();
const scale = new THREE.Vector3();matrix.decompose(position, quaternion, scale);
console.log('Position:', position);
console.log('Rotation:', quaternion);
console.log('Scale:', scale);
三、矩阵变换实战指南
3.1 变换组合原理
Three.js采用后乘的矩阵组合方式,理解执行顺序至关重要:
const mesh = new THREE.Mesh(geometry, material);// 正确的变换顺序:缩放 -> 旋转 -> 平移
mesh.scale.set(2, 2, 2);
mesh.rotation.x = Math.PI/4;
mesh.position.y = 10;// 等效矩阵计算:
const scaleMat = new THREE.Matrix4().makeScale(2, 2, 2);
const rotateMat = new THREE.Matrix4().makeRotationX(Math.PI/4);
const translateMat = new THREE.Matrix4().makeTranslation(0, 10, 0);// 矩阵组合顺序:T * R * S
const finalMatrix = translateMat.multiply(rotateMat).multiply(scaleMat);
mesh.matrix = finalMatrix;
3.2 矩阵堆栈管理
在复杂层级结构中,矩阵需要逐级传递:
function updateWorldMatrices(object, parentMatrix) {if (!parentMatrix) parentMatrix = new THREE.Matrix4();// 计算本地矩阵object.updateMatrix();// 组合世界矩阵object.matrixWorld.multiplyMatrices(parentMatrix, object.matrix);// 递归处理子对象for (let child of object.children) {updateWorldMatrices(child, object.matrixWorld);}
}
四、关键矩阵系统解析
4.1 模型视图投影矩阵(MVP)
// 获取三个关键矩阵
const modelMatrix = mesh.matrixWorld;
const viewMatrix = camera.matrixWorldInverse;
const projectionMatrix = camera.projectionMatrix;// 组合MVP矩阵
const mvpMatrix = new THREE.Matrix4().multiplyMatrices(projectionMatrix, viewMatrix).multiply(modelMatrix);
4.2 法线矩阵(Normal Matrix)
const normalMatrix = new THREE.Matrix3();
normalMatrix.getNormalMatrix(modelViewMatrix);// 在着色器中使用
material.onBeforeCompile = (shader) => {shader.uniforms.normalMatrix = { value: normalMatrix };shader.vertexShader = `uniform mat3 normalMatrix;${shader.vertexShader}`.replace('#include <beginnormal_vertex>', `objectNormal = normalMatrix * objectNormal;`);
};
五、性能优化策略
5.1 矩阵更新优化
// 禁用自动矩阵更新
mesh.matrixAutoUpdate = false;// 手动批量更新
function updateScene() {objects.forEach(obj => {obj.updateMatrix();obj.updateMatrixWorld(true); // 跳过子对象更新});
}
5.2 矩阵缓存重用
const _tempMatrix = new THREE.Matrix4();function calculateTransform(position, rotation, scale) {return _tempMatrix.compose(position, rotation, scale).clone();
}
六、常见问题诊断
6.1 变换顺序错误
症状:物体缩放导致旋转轴偏移
解决方案:
// 错误方式:
mesh.position.set(0, 5, 0);
mesh.rotation.y = Math.PI/2;
mesh.scale.set(2, 2, 2);// 正确方式:
mesh.scale.set(2, 2, 2);
mesh.rotation.y = Math.PI/2;
mesh.position.set(0, 5, 0);
6.2 矩阵更新遗漏
症状:子对象未跟随父级移动
解决方案:
parent.add(child);
parent.matrixWorldNeedsUpdate = true; // 强制更新世界矩阵
七、高阶应用实例
7.1 自定义矩阵动画
function matrixAnimation(mesh, duration) {const startMatrix = mesh.matrix.clone();const endMatrix = new THREE.Matrix4().makeRotationY(Math.PI).multiply(new THREE.Matrix4().makeTranslation(5, 0, 0));new TWEEN.Tween({ t: 0 }).to({ t: 1 }, duration).onUpdate(({ t }) => {mesh.matrix = startMatrix.clone().lerp(endMatrix, t);mesh.matrixWorldNeedsUpdate = true;}).start();
}
7.2 GPU矩阵计算
// 顶点着色器中使用自定义矩阵
const material = new THREE.ShaderMaterial({uniforms: {customMatrix: { value: new THREE.Matrix4() }},vertexShader: `uniform mat4 customMatrix;void main() {gl_Position = projectionMatrix * modelViewMatrix * customMatrix * vec4(position, 1.0);}`
});
八、调试与可视化工具
8.1 矩阵可视化
function printMatrix(label, matrix) {console.log(`${label}:`);const te = matrix.elements;for (let i = 0; i < 4; i++) {console.log(te[i*4].toFixed(2), te[i*4+1].toFixed(2),te[i*4+2].toFixed(2),te[i*4+3].toFixed(2));}
}
8.2 坐标系辅助显示
const axisHelper = new THREE.AxesHelper(5);
mesh.add(axisHelper);// 实时显示世界坐标系
function updateAxisHelper() {axisHelper.matrixWorld.copy(mesh.matrixWorld);axisHelper.matrixWorld.decompose(axisHelper.position,axisHelper.quaternion,axisHelper.scale);
}
九、最佳实践总结
- 优先使用高层API:尽量通过
position
、rotation
、scale
属性操作对象 - 谨慎直接修改矩阵:仅在必要时直接操作矩阵元素
- 注意更新顺序:修改属性后及时调用
updateMatrix()
- 重用矩阵对象:避免频繁创建新矩阵实例
- 理解空间转换链:
局部坐标 -> 世界坐标 -> 视图坐标 -> 裁剪坐标
通过掌握矩阵与向量的奥秘,开发者可以:
✅ 实现精准的物理碰撞检测
✅ 创建电影级动态光影效果
✅ 构建工业级数字孪生系统
✅ 开发复杂机械运动仿真
建议结合Three.js官方文档中的Matrix4和Vector3API参考进行实践,并利用浏览器开发者工具实时观察矩阵变化。
相关文章:
从零开始学习three.js(21):一文详解three.js中的矩阵Matrix和向量Vector
一、三维世界的数学基石 在Three.js的三维世界里,所有视觉效果的实现都建立在严密的数学基础之上。其中向量(Vector) 和矩阵(Matrix) 是最核心的数学工具,它们就像构建数字宇宙的原子与分子,支…...

应届本科生简历制作指南
一、找一个专业的简历模板 首先,你需要访问 Overleaf 的官方网站,也就是Overleaf, Online LaTeX Editor,进入页面后,点击注册按钮,按照提示填写相关信息来创建一个属于自己的账号,通常需要填写用户名、邮箱…...
VUE3+TS实现图片缩放移动弹窗
完整代码 使用VUE3、TS,实现将图片通过鼠标拖拽缩放以及选择缩放比例。 <template><div><el-dialogv-model"dialogVisible"title"查看图片":close-on-click-modal"false":close-on-press-escape"false"fu…...
大语言模型训练数据格式:Alpaca 和 ShareGPT
在大规模语言模型(LLM)的开发中,训练数据的质量和格式起着至关重要的作用。为了更好地理解和构建高质量的数据集,社区发展出了多种标准化的数据格式。其中,Alpaca 和 ShareGPT 是两种广泛使用的训练数据格式࿰…...
实现动态增QuartzJob,通过自定义注解调用相应方法
:::tip 动态增加Quartz定时任务,通过自定义注解来实现具体的定时任务方法调用。 ::: 相关依赖如下 <!-- 用来动态创建 Quartz 定时任务 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-start…...

PyTorch可视化工具——使用Visdom进行深度学习可视化
文章目录 前置环境Visdom安装并启动VisdomVisdom图形APIVisdom静态更新API详解通用参数说明使用示例Visdom动态更新API详解1. 使用updateappend参数2. ~~使用vis.updateTrace方法~~3. 完整训练监控示例 Visdom可视化操作散点图plot.scatter()散点图案例线性图vis.line()vis.lin…...
Qt无边框界面添加鼠标事件
在Qt中实现无边框窗口的鼠标事件处理,主要涉及窗口拖动和调整大小功能。以下是分步实现的代码示例: 1. 创建无边框窗口 首先,创建一个继承自QWidget的自定义窗口类,并设置无边框标志: #include <QWidget> #in…...

企业级爬虫进阶开发指南
企业级爬虫进阶开发指南 一、分布式任务调度系统的深度设计 1.1 架构设计原理 图表 1.2 核心代码实现与注释 分布式锁服务 # distributed_lock.py import redis import timeclass DistributedLock:def __init__(self, redis_conn):self.redis = redis_connself.lock_key = …...
Ubuntu ping网络没有问题,但是浏览器无法访问到网络
我这边是尝试清楚DNS缓存然后重新访问就可以了。 使用 resolvectl 刷新 DNS 缓存 在 Ubuntu 20.04 及更高版本中,可以使用以下命令来刷新 DNS 缓存: sudo resolvectl flush-caches 使用 systemd-resolve(适用于旧版本) 如果你…...

网络安全-等级保护(等保) 2-7 GB/T 25058—2019 《信息安全技术 网络安全等级保护实施指南》-2019-08-30发布【现行】
################################################################################ GB/T 22239-2019 《信息安全技术 网络安全等级保护基础要求》包含安全物理环境、安全通信网络、安全区域边界、安全计算环境、安全管理中心、安全管理制度、安全管理机构、安全管理人员、安…...

数据结构实验10.1:内部排序的基本运算
文章目录 一,实验目的二,实验内容1. 数据生成与初始化2. 排序算法实现(1)直接插入排序(2)二分插入排序(3)希尔排序(4)冒泡排序(5)快速…...
C#:多线程
一.线程常用概念 线程(Thread):操作系统执行程序的最小单位 进程(Process):程序在内存中的运行实例 并发(Concurrency):多个任务交替执行(单核CPU࿰…...
基于Zynq SDK的LWIP UDP组播开发实战指南
一、为什么选择LWIP组播? 在工业控制、智能安防、物联网等领域,一对多的高效数据传输需求日益增长。Zynq-7000系列SoC凭借其ARM+FPGA的独特架构,结合LWIP轻量级网络协议栈,成为嵌入式网络开发的理想选择。本文将带您实现: LWIP组播配置全流程动态组播组切换技术零拷贝数据…...
c#将json字符串转换为对象数组
在C#中,将JSON字符串转换为对象数组是一个常见的需求,特别是在处理来自Web API的响应或需要反序列化本地文件内容时。这可以通过使用Newtonsoft.Json(也称为Json.NET)库或.NET Core内置的System.Text.Json来完成。以下是如何使用这…...
机器学习在智能水泥基复合材料中的应用与实践
“机器学习在智能水泥基复合材料中的应用与实践” 课程 内容 机器学习基础模型与复合材料研究融合 机器学习在复合材料中的应用概述机器学习用于复合材料研究的流程复合材料数据收集与数据预处理 实例:数据的收集和预处理 复合材料机器学习特征工程与选择 实例&a…...

wps编辑技巧
1、编辑模式 2、图片提取方法:右键保存图片 可以直接右键保存下来看看是否是原始图,如果歪着的图,可能保存下来是正的,直接保存试下 3、加批注...

开放世界RPG:无缝地图与动态任务的拓扑学架构
目录 开放世界RPG:无缝地图与动态任务的拓扑学架构引言第一章 地图分块系统1.1 动态加载算法1.2 内存管理模型第二章 任务拓扑网络2.1 任务依赖图2.2 动态可达性分析第三章 NPC行为系统3.1 行为森林架构3.2 日程规划算法第四章 动态事件系统4.1 事件传播模型4.2 玩家影响指标第…...

【图像处理入门】1. 数字图像的本质:从像素到色彩模型
作为图像处理的开篇,本文将带你拆解数字图像的底层逻辑:从模拟图像到数字信号的神奇转换,到像素世界的微观构成,再到彩色图像的编码奥秘。通过 Python 代码实战,你将亲手触摸图像的 “基因”—— 像素值,并…...

(已解决:基于WSL2技术)Windows11家庭中文版(win11家庭版)如何配置和使用Docker Desktop
目录 问题现象: 问题分析: 拓展: 解决方法: 1、使用WSL2技术(亲测有效) 注意: 2、开启Hyper-V功能(未经亲测,待研究) 问题现象: 今天想在本…...

Ubuntu20.04部署KVM
文章目录 一. 环境准备关闭防火墙(UFW)禁用 SELinux更换镜像源检查 CPU 虚拟化支持 二. 安装KVM安装 KVM 及相关组件启动 libvirtd 服务验证安装创建虚拟机 一. 环境准备 4C8G,50G硬盘——VMware Workstation需要给虚拟机开启虚拟化引擎 roo…...

OpenCV CUDA 模块图像过滤------创建一个高斯滤波器函数createGaussianFilter()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::cuda::createGaussianFilter 是 OpenCV CUDA 模块中的一个工厂函数,用于创建一个高斯滤波器。这个滤波器可以用来平滑图像&#…...
计算机视觉与深度学习 | matlab实现ARIMA-WOA-CNN-LSTM时间序列预测(完整源码和数据)
以下是一个基于MATLAB的ARIMA-WOA-CNN-LSTM时间序列预测框架。由于完整代码较长,此处提供核心模块和实现思路,完整源码和数据可通过文末方式获取。 1. 数据准备(示例数据) 使用MATLAB内置的航空乘客数据集: % 加载数据 data = readtable(airline-passengers.csv); data …...

可视化图解算法43:数组中的逆序对
1. 题目 牛客网 面试笔试TOP101 描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007 数据范围&…...

【Python】使用Python实现调用API获取图片存储到本地
使用Python实现调用API获取图片存储到本地 目录 使用Python实现调用API获取图片存储到本地1、项目概述2、核心功能3、环境准备4、代码实现5、结果查看 1、项目概述 开发一个自动化工具,用于从JSON数据源中提取图像ID,通过调用指定API获取未经压缩的原始…...

腾讯2025年校招笔试真题手撕(一)
一、题目 有n 把钥匙,m 个锁,每把锁只能由一把特定的钥匙打开,其他钥匙都无法打开。一把钥匙可能可以打开多把锁,钥匙也可以重复使用。 对于任意一把锁来说,打开它的钥匙是哪一把是等概率的。但你无法事先知道是哪一把…...

Vue3 与 Vue2 区别
一、Vue3 与 Vue2 区别 对于生命周期来说,整体上变化不大,只是大部分生命周期钩子名称上 “on”,功能上是类似的。不过有一点需要注意,组合式API的Vue3 中使用生命周期钩子时需要先引入,而 Vue2 在选项API中可以直接…...
java集合详细讲解
Java 8 集合框架详解 Java集合框架是Java中最重要、最常用的API之一,Java 8对其进行了多项增强。下面我将全面讲解Java 8中的集合框架。 一、集合框架概述 Java集合框架主要分为两大类: Collection - 单列集合 List:有序可重复Set…...

嵌入式学习笔记 - STM32 U(S)ART 模块HAL 库函数总结
一 串口发送方式: ①轮训方式发送,也就是主动发送,这个容易理解,使用如下函数: HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout); ②中断方式发送ÿ…...

【VLNs篇】04:SayNav-为新环境中的动态规划到导航进行大型语言模型的基础构建
栏目内容论文标题SayNav: 为新环境中的动态规划到导航进行大型语言模型的基础构建 (SayNav: Grounding Large Language Models for Dynamic Planning to Navigation in New Environments)研究问题自主代理在未知环境中执行复杂导航任务(如MultiON)时&…...
MySQL中添加一个具有创建数据库权限的用户
要在MySQL中添加一个具有创建数据库权限的用户,可按以下步骤操作: 1. 登录MySQL 使用拥有足够权限(一般是root用户 )的账号登录到MySQL数据库。在命令行输入: mysql -u root -p然后输入对应的密码,即可进…...