ARTICLE DETAIL

资讯详情

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

three.js Vector4 四维向量完全解析:API 用法、源码原理与渲染管线应用

three.js Vector4 四维向量完全解析:API 用法、源码原理与渲染管线应用 three.js Vector4 四维向量完全解析API 用法、源码原理与渲染管线应用【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js本文基于 three.js 仓库中的官方 API 参考文档 Vector4 文档页 展开并结合 Vector4 源码 与 Vector4 单元测试 进行源码级验证。Vector4是 three.js 数学核心库中表示四维向量的类。与三维向量Vector3相比Vector4多出的w分量使其既能承载齐次坐标在Matrix4变换下保留透视语义也能在渲染管线中表达矩形视口与裁剪区域(x, y, width, height)。无论你在做自定义着色器后处理、解析缓冲几何数据还是理解 WebGL 渲染器的视口管理Vector4都是绕不开的基础工具。读完本文你将完整掌握Vector4的构造函数、全部公开方法、每个方法的底层公式与边界行为并通过单元测试与渲染器调用链看清它在 three.js 内部的真实用法。一、什么是 4D 向量Vector4的定位与典型用途Vector4表示一个有序四元组数字(x, y, z, w)。在 three.js 中它最常被用来表达以下三种含义4D 空间中的点具有四个独立坐标的点4D 空间中的方向与长度此时“长度”指从原点(0, 0, 0, 0)到(x, y, z, w)的欧几里得直线距离方向同样以原点为参照任意有序四元组例如视口/裁剪矩形(x, y, width, height)或 RGBA 颜色分量。值得特别注意的是w分量在图形学中的经典角色是齐次坐标。three.js 为构造函数的w提供了与其他分量不同的默认值1而x/y/z默认为0这一设计正是为了与齐次坐标的惯例保持一致——这一点从 构造函数实现 可以直观确认。另外从源码可见Vector4实现了迭代器协议Symbol.iterator 依次产出x, y, z, w因此你可以用for...of、数组解构等方式直接遍历向量分量const v new THREE.Vector4( 1, 2, 3, 4 ); for ( const c of v ) console.log( c ); // 依次输出 1 2 3 4 const [ x, y, z, w ] v; // 解构出四个分量二、构造与类型标识构造函数签名new Vector4( x : number, y : number, z : number, w : number )各参数说明如下参数含义默认值x向量的 x 分量0y向量的 y 分量0z向量的 z 分量0w向量的 w 分量1参数全部可选。根据 单元测试new Vector4()会得到(0, 0, 0, 1)而传入四个常数后四个分量一一对应相等。官方代码示例const a new THREE.Vector4( 0, 1, 0, 0 ); // 不传参数时将被初始化为 (0, 0, 0, 1) const b new THREE.Vector4(); const d a.dot( b );类型标识isVector4在类的静态初始化块中three.js 会为原型设置isVector4 true见 Vector4.js。这是一个贯穿整个 three.js 的类型标记惯例渲染器在很多地方并不依赖instanceof而是通过类似x.isVector4、v.isVector3的鸭子类型判断来决定处理分支。例如在 WebGLRenderer 的视口设置方法 中就存在if ( x.isVector4 ) { ... }的分支传入参数若是Vector4则直接按(x, y, z, w)解析为视口的(x, y, width, height)。这一点下文会继续展开。三、分量读写别名、索引与解构常规分量属性.x、.y、.z、.w分别是四个分量的直接属性。width/height别名.widthz的别名访问器 getter/setter.heightw的别名。两者的实现见 Vector4.js。这意味着当你把Vector4用作视口或矩形时既可以用v.z/v.w也可以用语义更清晰的v.width/v.height读写同一块存储const vp new THREE.Vector4( 0, 0, 800, 600 ); console.log( vp.z ); // 800 console.log( vp.width ); // 800等价于 vp.z vp.height 720; // 等价于 vp.w 720组件索引读写.getComponent( index : number ) : number返回指定索引的分量0→x、1→y、2→z、3→w.setComponent( index : number, value : number ) : Vector4按索引写入分量。注意索引越界时会抛出异常。源码中getComponent/setComponent的default分支统一抛出THREE.Vector4: index is out of range: index见 Vector4.js。单项 setter.setX( x )、.setY( y )、.setZ( z )、.setW( w )分别只更新对应分量全部返回this便于链式调用。四、构造式的赋值方法.set( x, y, z, w ) : Vector4一次性设置全部四个分量返回自身。.setScalar( scalar ) : Vector4把四个分量全部设为同一个标量值。常用于构造四维“常量向量”例如给四通道数据赋初值。.copy( v : Vector3 | Vector4 ) : Vector4从另一个向量拷贝分量。关键细节该方法允许传入Vector3当v.w为undefined时自动补写1见 Vector4.js。因此把一个三维向量拷贝进四维向量时w会被安全初始化为齐次坐标所需的1不会出现NaN。对应的 copy 单元测试 还验证了它是“深拷贝”——修改源向量不会影响目标。.clone() : Vector4返回一个复制当前分量的全新Vector4实例。五、向量与标量运算Vector4的运算方法与Vector3保持一致分为两类in-place 修改自身多数方法与把两个操作数的结果写入自身addVectors/subVectors/lerpVectors等。所有方法统一返回this方便链式调用。加法方法行为源码位置.add( v : Vector4 ) : Vector4逐分量加上vVector4.js.addScalar( s : number ) : Vector4每个分量都加sVector4.js.addScaledVector( v : Vector4, s : number ) : Vector4每个分量加上v对应分量与s的积即this v * sVector4.js.addVectors( a : Vector4, b : Vector4 ) : Vector4计算a b并写入自身Vector4.js其中addScaledVector是物理积分、重心迭代等算法中最常用的原子操作之一因为它只用一次方法调用就完成了“缩放 累加”且不产生临时对象。减法方法行为源码位置.sub( v : Vector4 ) : Vector4逐分量减去vVector4.js.subScalar( s : number ) : Vector4每个分量都减sVector4.js.subVectors( a : Vector4, b : Vector4 ) : Vector4计算a - b并写入自身Vector4.js减法在图形学中最直接的语义是求方向B.subVectors(end, start)得到从start指向end的向量。乘法与除法.multiply( v : Vector4 ) : Vector4与向量逐分量相乘Hadamard 积。.multiplyScalar( scalar ) : Vector4所有分量乘以同一标量。.divide( v : Vector4 ) : Vector4逐分量除以v的对应分量。.divideScalar( scalar : number ) : Vector4所有分量除以同一标量。关于.divideScalar有一个值得指出的实现细节它并非直接做除法而是委托给this.multiplyScalar( 1 / scalar )见 Vector4.js。也就是说它不包含除零保护传入0会产生Infinity/NaN。真正需要“安全归一化”的场景应改用.normalize()——后者内置了零长度保护。六、矩阵变换与四元数轴角Vector4的“进阶”用法.applyMatrix4( m : Matrix4 ) : Vector4用 4x4 矩阵变换本向量。Matrix4元素按列主序存储在e[0..15]中其数学本质是x m11·x m21·y m31·z m41·w y m12·x m22·y m32·z m42·w z m13·x m23·y m33·z m43·w w m14·x m24·y m34·z m44·w逐行实现见 Vector4.js。这正是齐次坐标的用法当w 1时w分量让矩阵的平移项e[12]、e[13]、e[14]即第四列前三行得以参与变换当w 0时则代表纯方向向量平移被忽略。因此用Vector4变换齐次坐标时务必把w设为1这正是构造函数默认值的由来而变换“方向”时则应设为0。.setFromMatrixPosition( m : Matrix4 ) : Vector4把矩阵的位移项读入向量x e[12]、y e[13]、z e[14]、w e[15]见 Vector4.js。它对e[15]的读取通常得到1因此可以直接取出变换矩阵的平移量。这一方法在 three.js 内部有真实的调用场景在 WebGLRenderer 的投影矩阵代码路径 中渲染器用_vector4.setFromMatrixPosition( object.matrixWorld )取出对象世界矩阵的平移作为深度排序依据在 LightShadow.js 中同样用它取出光源世界坐标。.setAxisAngleFromQuaternion( q : Quaternion ) : Vector4把一个归一化的四元数q转换成语义为“轴-角”的向量x/y/z存旋转轴w存旋转角弧度。实现见 Vector4.js当旋转角接近0或π即sqrt(1 - w²) 0.0001时退化处理为固定轴(1, 0, 0)。.setAxisAngleFromRotationMatrix( m : Matrix4 ) : Vector4同上但输入是纯旋转 4x4 矩阵左上 3x3 无缩放。源码在 Vector4.js 中实现了完备的轴-角提取算法先用反对称差判断是否存在奇异性再分别处理单位矩阵角为 0、180° 旋转以及一般情况下的acos角度求解且内置了0.01与0.1两个容差阈值用于容纳浮点舍入误差。const q new THREE.Quaternion().setFromEuler( new THREE.Euler( 0, Math.PI / 3, 0 ) ); const axisAngle new THREE.Vector4().setAxisAngleFromQuaternion( q ); // axisAngle.xyz ≈ (0, 1, 0)axisAngle.w ≈ Math.PI / 3七、度量点积与各种“长度”.dot( v : Vector4 ) : number计算两个向量的点积x·v.x y·v.y z·v.z w·v.w实现见 Vector4.js。这是本类最常用的运算之一v.dot(v)等于lengthSq()两个单位向量点积等于夹角余弦符号可判断方向性。.length() : number与.lengthSq() : numberlength()返回从原点到(x, y, z, w)的欧几里得长度即Math.sqrt(x² y² z² w²)Vector4.jslengthSq()返回长度的平方Vector4.js。官方文档特别提示当你需要比较多个向量的大小时应当用lengthSq()而非length()因为省去了一次Math.sqrt计算上更高效且判定结果不变。.manhattanLength() : number返回曼哈顿长度|x| |y| |z| |w|见 Vector4.js。适用于网格化空间中“只能沿轴移动”的距离度量。八、方向保持归一化与长度设定.normalize() : Vector4将向量化为单位向量长度为 1方向不变。其实现与divideScalar不同具有零向量保护normalize() { return this.divideScalar( this.length() || 1 ); }即当长度为0时以1作为除数避免产生NaN见 Vector4.js。在大量实时渲染代码中这条“零长度安全”保证让开发者可以放心地对可能退化的向量调用normalize。.setLength( length : number ) : Vector4先把向量归一化再缩放到指定的新长度Vector4.js等价于“保持方向、重设长度”。实现为normalize().multiplyScalar( length )。九、夹取Clamp三兄弟Vector4提供三种粒度的夹取方法全部基于MathUtils中导出的clamp函数见 Vector4.js方法夹取对象行为源码位置.clamp( min : Vector4, max : Vector4 ) : Vector4每个分量逐分量夹在min与max的对应分量之间前提是min/max各分量满足min maxVector4.js.clampScalar( minVal : number, maxVal : number ) : Vector4每个分量所有分量统一夹在[minVal, maxVal]区间内Vector4.js.clampLength( min : number, max : number ) : Vector4向量的长度若当前长度超出区间则按比例缩放向量使长度落在[min, max]方向不变Vector4.js其中clampLength的实现同样具备零长度保护divideScalar( length || 1 )先归一化长度 0 时按 1 处理再乘以夹取后的长度。典型应用是限制速度向量的大小只压长度、不改方向。十、线性插值Lerp系列方法语义源码位置.lerp( v : Vector4, alpha : number ) : Vector4在this与v之间插值结果写回自身alpha 0时为本向量alpha 1时为vVector4.js.lerpVectors( v1 : Vector4, v2 : Vector4, alpha : number ) : Vector4计算v1到v2之间的插值并写入自身alpha 0得v1alpha 1得v2Vector4.jsalpha是沿直线的比例因子通常取闭区间[0, 1]但源码并不限制越界——取区间外的值即为外推。两者都是逐分量执行a (b - a) * alpha。lerpVectors不会读自身旧值因此适合作为临时缓冲反复复用。const a new THREE.Vector4( 0, 0, 0, 1 ); const b new THREE.Vector4( 1, 1, 1, 1 ); const mid new THREE.Vector4().lerpVectors( a, b, 0.5 ); // mid (0.5, 0.5, 0.5, 1)十一、取整三件套与取反方法行为等价于.floor() : Vector4各分量向下取整Math.floor.ceil() : Vector4各分量向上取整Math.ceil.round() : Vector4各分量四舍五入Math.round.roundToZero() : Vector4各分量向零取整负数向上、正数向下Math.trunc四个方法分别见 Vector4.js常用于将连续坐标离散化到栅格。注意roundToZero与floor的差异只在负数上体现-1.7经floor变-2经roundToZero变-1。.negate() : Vector4分量全部取相反数Vector4.js。十二、相等性判断.equals( v : Vector4 ) : boolean逐个分量用严格相等比较x/y/z/w全部相等才返回true见 Vector4.js。注意这是精确比较不做任何容差处理涉及浮点运算结果之间的比较时应先对差值做长度判断如delta.lengthSq() eps单元测试中也从math-constants导入了专门的eps常量用于此类容差断言。十三、与数组及缓冲属性互转.fromArray( array : Array.number, offset : number 0 ) : Vector4按x array[offset]、y array[offset1]、z array[offset2]、w array[offset3]读取Vector4.js。.toArray( array : Array.number [], offset : number 0 ) : Array.number把四个分量顺序写入目标数组并返回该数组未提供array时新建数组Vector4.js。这两个方法与 BufferGeometry 的 attribute 数据布局完全一致是 CPU 端向几何数据填充/读取四分量数据的标准通道。对应测试见 Vector4.tests.js。.fromBufferAttribute( attribute : BufferAttribute, index : number ) : Vector4从 GPU 缓冲属性中读取第index个元素的四个分量内部调用attribute.getX/getY/getZ/getWVector4.js。这是从几何体缓冲中高效抽取四维数据例如 RGBA 顶点色、自定义四分量 attribute的标准方法。十四、随机向量.random() : Vector4四个分量分别赋值为[0, 1)区间含 0 不含 1的伪随机数Vector4.js。随机粒子系统、程序化初值等场景可直接使用。十五、渲染管线中的真实应用视口与裁剪矩形Vector4在 three.js 内部最主要的工程用途是把“四元组(x, y, width, height)”编码成单一对象用于描述视口viewport与裁剪区域scissor。在 WebGLRenderer 内部状态管理 中渲染器持有_viewport new Vector4( 0, 0, _width, _height )与_scissor作为缓存对象而setViewport/setScissor公开方法的参数类型都接受Vector4 | number通过x.isVector4做类型分派见 WebGLRenderer.js。换句话说用户代码传入的Vector4会直接按列(x, y, z, w)语义被解析为(x, y, width, height)传给底层gl.viewport。在阴影渲染一侧LightShadow 的默认视口集合 同样以new Vector4( 0, 0, 1, 1 )表示规范化矩形全图一个阴影视口。这也是Vector4提供.width/.height别名的根本原因当它作为“矩形”使用时z读作宽度、w读作高度代码可读性显著提升。十六、从单元测试看契约与边界行为Vector4的单元测试位于 test/unit/src/math/Vector4.tests.jsQUnit 组织全文约 650 行覆盖了本文介绍的全部公开方法可用于快速验证行为契约实例化与类型new Vector4()默认为(0, 0, 0, 1)isVector4为真L17-L39矩阵变换与位移提取applyMatrix4多组平移/缩放矩阵断言与setFromMatrixPosition验证L181-L245数组互转fromArray的默认/带偏移读取toArray的默认新建与带偏移写入L378-L415标量运算multiplyScalar/divideScalar的正负标量验证L533-L556。这些测试与测试工具常量math-constants.js提供x/y/z/w样本与容差eps共同保证了Vector4的数学行为与文档描述一致。十七、小结方法速查总表分类方法构造new Vector4(x, y, z, w)默认0,0,0,1赋值set、setScalar、copy、clone、setX/Y/Z/W、setComponent、getComponent加法add、addScalar、addVectors、addScaledVector减法sub、subScalar、subVectors乘法/除法multiply、multiplyScalar、divide、divideScalar矩阵/轴角applyMatrix4、setFromMatrixPosition、setAxisAngleFromQuaternion、setAxisAngleFromRotationMatrix度量dot、length、lengthSq、manhattanLength方向控制normalize、setLength夹取clamp、clampScalar、clampLength插值lerp、lerpVectors取整floor、ceil、round、roundToZero、negate判断/转换equals、fromArray、toArray、fromBufferAttribute、random协议isVector4标记、[Symbol.iterator]产出 x/y/z/w多数方法都返回向量自身天然支持链式调用例如v.copy(a).addScaledVector(b, 0.5).clampLength(0, 10)。建议把Vector4与同目录下的 Vector3 文档若需三维运算、Matrix4、Quaternion结合使用四维向量的矩阵与轴角转换能力正是它们在数学上协同工作的接口所在。深入阅读源码可直接查看 src/math/Vector4.js需要更多示例可翻看 src/math 目录下同族类的实现风格。【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表