从零开始学习three.js(21):一文详解three.js中的矩阵Matrix和向量Vector

news2025/5/23 22:24:29

一、三维世界的数学基石

在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中的矩阵主要用于描述空间变换关系,以下是关键矩阵类型:

矩阵类型维度应用场景
Matrix33x3UV变换、法线矩阵
Matrix44x4模型视图投影矩阵(核心)
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
    );
}

九、最佳实践总结

  1. 优先使用高层API:尽量通过positionrotationscale属性操作对象
  2. 谨慎直接修改矩阵:仅在必要时直接操作矩阵元素
  3. 注意更新顺序:修改属性后及时调用updateMatrix()
  4. 重用矩阵对象:避免频繁创建新矩阵实例
  5. 理解空间转换链局部坐标 -> 世界坐标 -> 视图坐标 -> 裁剪坐标

通过掌握矩阵与向量的奥秘,开发者可以:
✅ 实现精准的物理碰撞检测
✅ 创建电影级动态光影效果
✅ 构建工业级数字孪生系统
✅ 开发复杂机械运动仿真

建议结合Three.js官方文档中的Matrix4和Vector3API参考进行实践,并利用浏览器开发者工具实时观察矩阵变化。

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

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

相关文章

应届本科生简历制作指南

一、找一个专业的简历模板 首先&#xff0c;你需要访问 Overleaf 的官方网站&#xff0c;也就是Overleaf, Online LaTeX Editor&#xff0c;进入页面后&#xff0c;点击注册按钮&#xff0c;按照提示填写相关信息来创建一个属于自己的账号&#xff0c;通常需要填写用户名、邮箱…

PyTorch可视化工具——使用Visdom进行深度学习可视化

文章目录 前置环境Visdom安装并启动VisdomVisdom图形APIVisdom静态更新API详解通用参数说明使用示例Visdom动态更新API详解1. 使用updateappend参数2. ~~使用vis.updateTrace方法~~3. 完整训练监控示例 Visdom可视化操作散点图plot.scatter()散点图案例线性图vis.line()vis.lin…

企业级爬虫进阶开发指南

企业级爬虫进阶开发指南 一、分布式任务调度系统的深度设计 1.1 架构设计原理 图表 1.2 核心代码实现与注释 分布式锁服务 # distributed_lock.py import redis import timeclass DistributedLock:def __init__(self, redis_conn):self.redis = redis_connself.lock_key = …

网络安全-等级保护(等保) 2-7 GB/T 25058—2019 《信息安全技术 网络安全等级保护实施指南》-2019-08-30发布【现行】

################################################################################ GB/T 22239-2019 《信息安全技术 网络安全等级保护基础要求》包含安全物理环境、安全通信网络、安全区域边界、安全计算环境、安全管理中心、安全管理制度、安全管理机构、安全管理人员、安…

数据结构实验10.1:内部排序的基本运算

文章目录 一&#xff0c;实验目的二&#xff0c;实验内容1. 数据生成与初始化2. 排序算法实现&#xff08;1&#xff09;直接插入排序&#xff08;2&#xff09;二分插入排序&#xff08;3&#xff09;希尔排序&#xff08;4&#xff09;冒泡排序&#xff08;5&#xff09;快速…

wps编辑技巧

1、编辑模式 2、图片提取方法&#xff1a;右键保存图片 可以直接右键保存下来看看是否是原始图&#xff0c;如果歪着的图&#xff0c;可能保存下来是正的&#xff0c;直接保存试下 3、加批注

开放世界RPG:无缝地图与动态任务的拓扑学架构

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

【图像处理入门】1. 数字图像的本质:从像素到色彩模型

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

(已解决:基于WSL2技术)Windows11家庭中文版(win11家庭版)如何配置和使用Docker Desktop

目录 问题现象&#xff1a; 问题分析&#xff1a; 拓展&#xff1a; 解决方法&#xff1a; 1、使用WSL2技术&#xff08;亲测有效&#xff09; 注意&#xff1a; 2、开启Hyper-V功能&#xff08;未经亲测&#xff0c;待研究&#xff09; 问题现象&#xff1a; 今天想在本…

Ubuntu20.04部署KVM

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

OpenCV CUDA 模块图像过滤------创建一个高斯滤波器函数createGaussianFilter()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::cuda::createGaussianFilter 是 OpenCV CUDA 模块中的一个工厂函数&#xff0c;用于创建一个高斯滤波器。这个滤波器可以用来平滑图像&#…

可视化图解算法43:数组中的逆序对

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

【Python】使用Python实现调用API获取图片存储到本地

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

腾讯2025年校招笔试真题手撕(一)

一、题目 有n 把钥匙&#xff0c;m 个锁&#xff0c;每把锁只能由一把特定的钥匙打开&#xff0c;其他钥匙都无法打开。一把钥匙可能可以打开多把锁&#xff0c;钥匙也可以重复使用。 对于任意一把锁来说&#xff0c;打开它的钥匙是哪一把是等概率的。但你无法事先知道是哪一把…

Vue3 与 Vue2 区别

一、Vue3 与 Vue2 区别 对于生命周期来说&#xff0c;整体上变化不大&#xff0c;只是大部分生命周期钩子名称上 “on”&#xff0c;功能上是类似的。不过有一点需要注意&#xff0c;组合式API的Vue3 中使用生命周期钩子时需要先引入&#xff0c;而 Vue2 在选项API中可以直接…

嵌入式学习笔记 - STM32 U(S)ART 模块HAL 库函数总结

一 串口发送方式&#xff1a; ①轮训方式发送&#xff0c;也就是主动发送&#xff0c;这个容易理解&#xff0c;使用如下函数&#xff1a; HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout); ②中断方式发送&#xff…

【VLNs篇】04:SayNav-为新环境中的动态规划到导航进行大型语言模型的基础构建

栏目内容论文标题SayNav: 为新环境中的动态规划到导航进行大型语言模型的基础构建 (SayNav: Grounding Large Language Models for Dynamic Planning to Navigation in New Environments)研究问题自主代理在未知环境中执行复杂导航任务&#xff08;如MultiON&#xff09;时&…

oracle使用SPM控制执行计划

一 SPM介绍 Oracle在11G中推出了SPM&#xff08;SQL Plan management&#xff09;,SPM是一种主动的稳定执行计划的手段&#xff0c;能够保证只有被验证过的执行计划才会被启用&#xff0c;当由于种种原因&#xff08;比如统计信息的变更&#xff09;而导致目标SQL产生了新的执…

Openwrt下使用ffmpeg配合自建RTSP服务器实现推流

目前在Openwrt下时mjpg_streamer实现UVC摄像头转网络摄像头的方案很多&#xff0c;这种方案视频服在路由模组中&#xff0c;在局域网中使用很方便。但是对于需要远程监控管理的情况&#xff0c;mjpg_streamer不适应&#xff0c;因为不在局域网中的播放器无法访问到路由模组中的…

wifi 如果检查失败,UI 就会出现延迟或缺失打勾的现象。

问题&#xff1a;connectedSsid 的初始化依赖 onCreate 中的状态检查&#xff0c;如果检查失败&#xff0c;UI 就会出现延迟或缺失打勾的现象。 WIFI界面上上的一个标识代表成功连接。重启后出现偶尔不打勾的情况。 原始代码&#xff1a; // if (connectedSsid !…