十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

【three.js教程】Three.js 矩阵变换:position/quaternion/scale 和 matrix 到底怎么配合

【three.js教程】Three.js 矩阵变换:position/quaternion/scale 和 matrix 到底怎么配合 Three.js 矩阵变换position/quaternion/scale 和 matrix 到底怎么配合原文出处Three.js Manual – Matrix transformations本文基于官方手册「Matrix transformations」章节整理用通俗方式带你看懂Three.js 怎么用一个 4×4 矩阵存下位置/旋转/缩放、两种改变换的方式分别怎么用、对象矩阵和世界矩阵差在哪以及为什么旋转永远用四元数存。写在前面你在 Three.js 里让一个物体移动、旋转、缩放本质上都是在操作它的矩阵matrix。每个Object3D身上都有一块矩阵把「位置、旋转、缩放」这三件事编码成一个 4×4 数学对象。这篇就讲清楚这矩阵从哪来、怎么改、对象矩阵和世界矩阵有什么区别、以及旋转为什么老跟quaternion绑在一起。顺带呼应一下前面「运行时更新」那篇matrixAutoUpdate这套开关本篇会讲得更底层。一、矩阵是什么一个 4×4 存下三大变换Three.js 用矩阵来编码三维变换——平移position、旋转、缩放。每个Object3D实例都有个matrix存的就是这个对象的位置、旋转和缩放。更新一个对象的变换有两条路可走。二、方式一改便捷属性让引擎重算矩阵最常用绝大多数情况你都用这套直接改position、quaternion、scale这几个「便捷属性」让 three.js 自己从它们重算出矩阵。object.position.copy(start_position);object.quaternion.copy(quaternion);默认情况下matrixAutoUpdate是true矩阵会被自动重新计算。但如果你确定对象是静态的或者想自己掌控「什么时候重算」把它关掉能获得更好的性能object.matrixAutoUpdatefalse;关掉之后改完属性要手动刷新矩阵object.updateMatrix();这正是「运行时更新」那篇提过的套路静态对象关掉自动更新只在需要时updateMatrix()一次省掉每帧的矩阵运算。三、方式二直接改 matrix进阶如果你更习惯直接操作矩阵本身Matrix4类提供了一堆方法。比如从四元数造旋转、再设位置object.matrix.makeRotationFromQuaternion(quaternion);object.matrix.setPosition(start_position);object.matrixAutoUpdatefalse;matrixAutoUpdate必须设为false——否则引擎每帧又从position/scale重算把你手改的矩阵覆盖掉千万别调updateMatrix()。一旦调用它会从position、scale等属性重新算矩阵把你手动做的修改全冲掉。换句话说方式一和方式二互斥——要么让引擎从属性算矩阵要么你自己改矩阵并关掉自动重算二选一。四、对象矩阵 vs 世界矩阵这是新手最容易混的概念对象的matrix存的是相对于父级的变换。如果一个物体挂在scene下它的父级是场景那 matrix 基本就是「世界里的样子」但如果它挂在另一个会动的物体比如一个 Group下它的 matrix 只是「相对那个父物体」的偏移。世界矩阵world matrix要拿到对象在世界坐标下的真正变换得访问它的世界矩阵。当父级或子级的变换发生变化时可以调用下面这个方法让子对象的世界矩阵刷新object.updateMatrixWorld();另外可以通过applyMatrix4()直接用一个Matrix4去变换对象。但要注意一个坑这个方法底层依赖Matrix4.decompose()把矩阵分解回 position/quaternion/scale并不是所有矩阵都能这么分解。例如当对象有一个非均匀缩放non-uniform scale的父级时它的世界矩阵可能无法分解applyMatrix4()就不适用了。划重点非均匀缩放scale三个分量不相等比如 x2、y1、z1会污染子节点的世界矩阵分解做矩阵运算时要特别小心。五、Rotation 与 Quaternion为什么旋转永远用四元数Three.js 表示三维旋转有两套欧拉角Euler angles直观但有个著名毛病叫万向节死锁gimbal lock——某些角度配置下会丢失一个旋转自由度导致物体绕某一轴转不动。四元数Quaternion没有万向节死锁问题。所以 Three.js 的规则是对象的旋转永远存在它的quaternion里欧拉角只是个方便你输入的界面。早版本里有个useQuaternion属性设成false就让矩阵从欧拉角算。这个做法已经被废弃。现在想从欧拉角设旋转用这个方法它会同步更新四元数object.setRotationFromEuler(euler);记忆法你可以用欧拉角「下达指令」但引擎内部始终以四元数为准存储和执行。总结矩阵变换速查主题要点代码/开关存储每个 Object3D 用 4×4matrix存 position/rotation/scale—方式一改position/quaternion/scale引擎重算矩阵matrixAutoUpdatetrue默认静态可设false后手动updateMatrix()方式二直接改matrixmatrixAutoUpdatefalse且绝不调updateMatrix()对象 vs 世界matrix相对父级世界变换要刷世界矩阵updateMatrixWorld()旋转永远存于quaternion欧拉角只是输入界面用setRotationFromEuler()替代废弃的useQuaternion延伸阅读three.js docs – Object3D.matrixthree.js docs – Object3D.matrixAutoUpdatethree.js docs – Object3D.updateMatrixWorldthree.js docs – Matrix4three.js docs – Quaternion
返回列表