Three.js Vector2 二维向量完全指南:从源码到实战
Three.js Vector2 二维向量完全指南从源码到实战【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.jsVector2是 three.js 中表示二维向量的核心数学类一个二维向量就是一对有序数字标记为 x 和 y在 src/math/Vector2.js 中实现。它贯穿了三维渲染的各个环节鼠标/触控归一化坐标NDC、UV 纹理坐标、Canvas 尺寸、曲线参数、光照阴影映射偏移等。阅读本文你将掌握Vector2的构造、全部属性与 50 余个方法含链式调用、角度/长度/插值/矩阵变换并能将它与 Raycaster、OrbitControls、几何体/曲线等实际模块结合使用写出可直接运行的实战代码。文档原始出处本仓库 docs/pages/Vector2.html.md完整参考页见 docs/pages/Vector2.html。一、Vector2 是什么二维向量能表示很多事物在 three.js 中常见用途包括二维空间中的一个点平面上的位置平面上的方向与长度——在 three.js 中长度恒为从(0, 0)到(x, y)的欧几里得距离直线距离方向也是从(0, 0)指向(x, y)任意一对有序数字。除此之外二维向量还可以表示动量向量、复数等但上述三种是 three.js 中最常见的用法。从源码结构看src/math/Vector2.jsVector2本身只存两个数字属性但通过static块在原型上挂了一个类型标识Vector2.prototype.isVector2 true;这为引擎内部做类型检测提供了依据例如isVector2会被 test/unit/src/math/Vector2.tests.js 断言验证。可迭代特性在源码末尾src/math/Vector2.jsVector2定义了一个生成器*[ Symbol.iterator ]() { yield this.x; yield this.y; }也就是说遍历一个向量实例会按顺序产出(x, y)两个分量const v new THREE.Vector2( 0, 1 ); const array [ ...v ]; // [ 0, 1 ]该行为由 test/unit/src/math/Vector2.tests.js 中的iterable测试用例验证。基础代码示例const a new THREE.Vector2( 0, 1 ); // 不传参数时初始化为 (0, 0) const b new THREE.Vector2(); const d a.distanceTo( b ); // 计算 a 到 b 的距离二、构造函数与属性构造函数new Vector2( x : number, y : number )构造一个新的二维向量参数说明默认值x该向量的 x 值0y该向量的 y 值0从源码可见构造器默认参数即为x 0, y 0src/math/Vector2.js且x、y被保存为公开属性。属性一览属性类型说明.xnumber该向量的 x 值.ynumber该向量的 y 值.widthnumberx的别名getter/setter读写均等价于.x见 src/math/Vector2.js.heightnumbery的别名读写均等价于.y见 src/math/Vector2.jswidth/height别名在 test/unit/src/math/Vector2.tests.js 中专门有测试设置width/height会同步修改x/y。三、方法全解按功能分组以下方法均直接作用于实例本身并返回this支持链式调用除非特别注明返回值类型。3.1 赋值与复制方法返回说明.set( x, y )Vector2设置 x、y 分量.setScalar( scalar )Vector2将两个分量都设为同一个值.setX( x )Vector2仅设置 x 分量.setY( y )Vector2仅设置 y 分量.setComponent( index, value )Vector2按下标设置分量0表示 x1表示 y越界抛出THREE.Vector2: index is out of rangesrc/math/Vector2.js.getComponent( index )number按下标读取分量越界同样抛错src/math/Vector2.js.clone()Vector2返回一份新的、值相同的向量副本.copy( v )Vector2把v的值复制到本实例.equals( v )boolean判断两向量的 x、y 是否全等源码提示clone()使用new this.constructor( this.x, this.y )src/math/Vector2.js因此对Vector2的子类也能正确克隆。setComponent/getComponent的越界异常行为有对应单元测试test/unit/src/math/Vector2.tests.js。3.2 加减乘除与数乘方法说明.add( v )加上向量v.addScalar( s )每个分量都加标量s.addVectors( a, b )计算a b存入本实例.addScaledVector( v, s )本实例加上v * s向量数乘后相加.sub( v )减去向量v.subScalar( s )每个分量都减标量s.subVectors( a, b )计算a - b存入本实例.multiply( v )逐分量相乘component-wise.multiplyScalar( scalar )每个分量都乘标量.divide( v )逐分量相除.divideScalar( scalar )每个分量都除以标量实现细节divideScalar实际是this.multiplyScalar( 1 / scalar )src/math/Vector2.js因此传入0会产生Infinity乘法路径使用时需注意。这些运算的期望值均有对应单元测试覆盖见 test/unit/src/math/Vector2.tests.js 中的add/sub/multiply/divide/setScalar/addScalar/subScalar用例。3.3 长度与距离方法返回说明.length()number从(0,0)到(x,y)的欧几里得长度Math.sqrt( x*x y*y ).lengthSq()number长度的平方不开方效率更高.manhattanLength()number曼哈顿长度|x| |y|.distanceTo( v )number本实例到v的欧几里得距离.distanceToSquared( v )number距离的平方.manhattanDistanceTo( v )number到v的曼哈顿距离|x1-x2| |y1-y2|性能要点文档原话如果只是比较两个距离的大小请比较平方距离lengthSq()/distanceToSquared()因为省去开方更高效。该建议同样见于length()/lengthSq()的源码注释src/math/Vector2.js。3.4 点积、叉积与角度方法返回说明.dot( v )number点积x*v.x y*v.ysrc/math/Vector2.js.cross( v )number叉积x*v.y - y*v.xsrc/math/Vector2.js。注意二维叉积结果是标量z 分量.angle()number该向量相对于正 x 轴的夹角弧度.angleTo( v )number该向量与v的夹角弧度结果范围[0, π]angleTo的实现值得注意src/math/Vector2.js先求两向量长度之积作为分母若分母为0返回π/2再通过acos( clamp( dot / denominator, -1, 1 ) )计算clamp 用于规避浮点数值误差。单元测试覆盖了同向0、反向π、正交π/2与 45° 等情形test/unit/src/math/Vector2.tests.js。3.5 归一化、定向与旋转方法说明.normalize()转换为单位向量长度变为1方向不变.setLength( length )保持方向不变把长度设为指定值.negate()取反x -xy -y.rotateAround( center, angle )绕点center旋转angle弧度.random()将每个分量设为[0, 1)的伪随机数不含 1实现细节src/math/Vector2.jsnormalize()是this.divideScalar( this.length() || 1 )当长度为 0 时除以 1 兜底避免产生NaN。setLength是normalize().multiplyScalar( length )src/math/Vector2.js对应测试验证了零向量调用setLength后长度仍为 0而空参调用会产生NaNtest/unit/src/math/Vector2.tests.js。rotateAroundsrc/math/Vector2.js先平移至以center为原点再做标准二维旋转const c Math.cos( angle ), s Math.sin( angle ); const x this.x - center.x; const y this.y - center.y; this.x x * c - y * s center.x; this.y x * s y * c center.y;3.6 钳制与最值方法说明.min( v )逐分量取较小值Math.min( this.x, v.x ).max( v )逐分量取较大值.clamp( min, max )逐分量钳制到[min.x, max.x]与[min.y, max.y]区间假设min max逐分量比较.clampScalar( minVal, maxVal )每个分量都钳制到[minVal, maxVal].clampLength( min, max )把向量长度钳制到[min, max]方向不变clamp*系列底层都调用MathUtils.clampsrc/math/Vector2.js。clampLength的实现是先归一化再按钳制后的长度缩放divideScalar( length || 1 ).multiplyScalar( clamp( length, min, max ) )同样对零向量做了兜底。min/max/clamp 的断言见 test/unit/src/math/Vector2.tests.js。3.7 取整方法说明.floor()向下取整Math.floor.ceil()向上取整Math.ceil.round()四舍五入Math.round.roundToZero()向零取整负数向上、正数向下Math.truncroundToZero在源码中用Math.trunc实现src/math/Vector2.js与floor/ceil/round的差异在 test/unit/src/math/Vector2.tests.js 中有详尽的边界值断言如-0.5取整结果各不相同。3.8 线性插值方法说明.lerp( v, alpha )在本实例与v之间插值alpha 0得到本向量alpha 1得到v.lerpVectors( v1, v2, alpha )在v1与v2之间插值并存入本实例alpha 0得到v1alpha 1得到v2alpha通常取闭区间[0, 1]百分比位置实现见 src/math/Vector2.js插值端点与中间值的正确性由 test/unit/src/math/Vector2.tests.js 验证。3.9 矩阵变换与数组转换方法说明.applyMatrix3( m )用 3x3 矩阵m变换本向量隐式补第 3 个分量为1.fromArray( array, offset 0 )从数组读取x array[offset]y array[offset 1].toArray( array [], offset 0 )写入数组array[offset] xarray[offset 1] y不传数组时新建并返回.fromBufferAttribute( attribute, index )从BufferAttribute的第index个顶点读取分量内部调用attribute.getX(index)/getY(index)applyMatrix3的展开式src/math/Vector2.jsthis.x e[ 0 ] * x e[ 3 ] * y e[ 6 ]; this.y e[ 1 ] * x e[ 4 ] * y e[ 7 ];其中e为矩阵元素列主序数组平移由第 6、7 项贡献。单元测试使用矩阵[2,3,5,7,11,13,17,19,23]验证了结果(18, 60)test/unit/src/math/Vector2.tests.js。fromArray/toArray/fromBufferAttribute在几何数据处理中非常常用其偏移语义均有测试覆盖test/unit/src/math/Vector2.tests.js。四、实战场景Vector2 在 three.js 生态中的典型应用4.1 鼠标/触控归一化坐标与 Raycaster 拾取Vector2最经典的实战场景是射线拾取。在 examples/webgl_interactive_cubes.html 中const pointer new THREE.Vector2(); // ... function onPointerMove( event ) { pointer.x ( event.clientX / window.innerWidth ) * 2 - 1; pointer.y - ( event.clientY / window.innerHeight ) * 2 1; } raycaster.setFromCamera( pointer, camera );把像素坐标映射到 NDC归一化设备坐标后传给 Raycaster.setFromCamera其参数coords类型正是Vector2。Raycaster的求交结果intersection上的.uv、.uv1属性也是Vector2src/core/Raycaster.js。4.2 交互控制器内部运算OrbitControls 内部用一组Vector2暂存旋转/平移/缩放操作的起止点与增量_rotateStart、_rotateDelta、_panDelta等并把指针位置换算成 NDCthis._mouse.x ( dx / w ) * 2 - 1。DragControls 用_pointer、_diff、_previousPointer三个Vector2计算拖拽位移。MapControls 与 ArcballControls 同样以Vector2承载光标/指针坐标。4.3 几何体、曲线与材质参数Vector2是众多几何体与曲线的输入参数类型曲线控制点QuadraticBezierCurve、CubicBezierCurve、LineCurve、SplineCurve、EllipseCurvesrc/extras/curves 目录几何体尺寸/中心CircleGeometry、RingGeometry、CylinderGeometry、LatheGeometry、TubeGeometry等的center、radius参数材质 UV 参数MeshPhongMaterial、MeshStandardMaterial、MeshPhysicalMaterial等材质的uvOffset/uvScale阴影贴图LightShadow的mapSize与offsetsrc/lights/LightShadow.js数学工具Box2 的 min/max 角点即Vector2Frustum、BufferGeometry中也大量使用。4.4 二维 UI 与平面几何对 2D 平面元素可直接把Vector2当作坐标点使用配合width/height别名语义化表达矩形尺寸const size new THREE.Vector2( 1024, 768 ); size.width; // 1024等价于 size.x size.height; // 768等价于 size.y五、快速参考表为便于速查汇总全部方法签名类别方法赋值setsetScalarsetXsetYsetComponentgetComponentclonecopyequals算术addaddScalaraddVectorsaddScaledVectorsubsubScalarsubVectorsmultiplymultiplyScalardividedivideScalar长度/距离lengthlengthSqmanhattanLengthdistanceTodistanceToSquaredmanhattanDistanceTo角度/积dotcrossangleangleTo方向/旋转normalizesetLengthnegaterotateAroundrandom钳制/最值minmaxclampclampScalarclampLength取整floorceilroundroundToZero插值lerplerpVectors矩阵/数组applyMatrix3fromArraytoArrayfromBufferAttribute除dot、cross、length、lengthSq、manhattanLength、distanceTo、distanceToSquared、manhattanDistanceTo、angle、angleTo、equals、clone、getComponent、toArray返回标量或新对象外其余方法均返回本实例引用可无限链式调用例如const v new THREE.Vector2( 3, 4 ) .normalize() // (0.6, 0.8) .multiplyScalar( 10 ) // (6, 8) .add( new THREE.Vector2( 1, 1 ) ); // (7, 9)六、相关资源导航文档页面docs/pages/Vector2.html渲染版源码实现src/math/Vector2.js单元测试test/unit/src/math/Vector2.tests.js依赖工具MathUtils.clamp定义于 src/math/MathUtils.js同类向量三维向量 Vector3src/math/Vector3.js、四维向量 Vector4【免费下载链接】three.jsJavaScript 3D Library.项目地址: https://gitcode.com/GitHub_Trending/th/three.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考