Threejs源码系列- MathUtils(2)

degToRad函数

用于将角度(度)转换为弧度,是 Three.js 中处理角度与弧度转换的基础工具函数。

js 复制代码
/**
 *
 * @param {number} degrees - 角度(度)
 * @return {number} 弧度
 */
function degToRad( degrees ) {

	return degrees * DEG2RAD;

}

应用场景

  • 在设置相机视场角(FOV)时,将用户输入的度数转换为弧度(如 camera.fov = MathUtils.degToRad(75))。
  • 物体旋转时,将直观的角度值(如 "旋转 45 度")转换为 Three.js 旋转属性所需的弧度(如 mesh.rotation.y = MathUtils.degToRad(45))
  • 配合三角函数(如 Math.sinMath.cos)使用时,将角度参数转换为函数所需的弧度单位。

该函数逻辑简洁,是 Three.js 中角度单位转换的核心工具,确保了开发过程中角度参数的一致性和正确性。

radToDeg函数

用于将弧度转换为角度,是 Three.js 中角度单位转换的核心工具函数。

js 复制代码
/**
 *
 * @param {number} radians - 弧度
 * @return {number} 角度(度)
 */
function radToDeg( radians ) {

	return radians * RAD2DEG;

}

应用场景

  • 在获取物体旋转角度(如 mesh.rotation.y 以弧度存储)后,转换为角度用于显示或交互(如 UI 展示 "当前旋转 45 度")。
  • 配合三角函数计算结果的转换(如 Math.sin 返回的弧度相关值,通过此函数转为角度)。
  • 调试时将程序内部的弧度值转换为可读的角度,便于理解和验证。

该函数逻辑简洁,与 degToRad 函数形成互补,共同确保 Three.js 中角度单位转换的准确性。

isPowerOfTwo函数

用于判断一个数字是否为 2 的幂(Power of Two,POT),是 Three.js 中常用的数学工具函数。

js 复制代码
/**
 * @param {number} value - 待检查的数字
 * @return {boolean} 
 */
function isPowerOfTwo( value ) {

	return ( value & ( value - 1 ) ) === 0 && value !== 0;

}

应用场景

在 Three.js 中常用于:

  • 检查纹理尺寸是否为 2 的幂(许多 WebGL 实现对非 2 的幂纹理有兼容性限制)。
  • 优化算法(如在需要按 2 的幂对齐的场景中,提前验证输入合法性)。
  • 图形渲染相关的性能优化(如 mipmap 生成通常要求纹理尺寸为 2 的幂)。

该函数是判断 2 的幂的经典实现,利用二进制特性实现了高效且简洁的逻辑。

示例

js 复制代码
console.log(isPowerOfTwo(8)); // 输出: true
console.log(isPowerOfTwo(10)); // 输出: false
console.log(isPowerOfTwo(0)); // 输出: false

ceilPowerOfTwo函数

用于计算大于或等于给定数值的最小 2 的幂(Power of Two,POT),是 Three.js 中处理 2 的幂运算的重要工具函数。

js 复制代码
/**
 * @param {number} value - 待处理的数值
 * @return {number} 返回值为 "大于或等于 value 的最小 2 的幂"(例如,输入 10 时返回 16,输入 8 时返回 8)。
 */
function ceilPowerOfTwo( value ) {

	return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );

}

应用场景

在 Three.js 中常用于:

  • 纹理处理:将非 2 的幂尺寸(如 100x100)转换为最小的 2 的幂尺寸(如 128x128),以兼容需要 POT 纹理的 WebGL 特性(如 mipmap)。
  • 性能优化:在需要按 2 的幂对齐的数据结构(如缓冲区)中,确保尺寸符合要求以提升计算效率。
  • 算法适配:某些图形算法(如 FFT、分形生成)仅对 2 的幂长度的输入有效,需提前转换。

示例

js 复制代码
console.log(ceilPowerOfTwo(10)); // 输出: 16
console.log(ceilPowerOfTwo(16)); // 输出: 16
console.log(ceilPowerOfTwo(7)); // 输出: 8

floorPowerOfTwo函数

用于计算小于或等于给定数值的最大 2 的幂(Power of Two,POT),是 Three.js 中处理 2 的幂运算的重要工具函数,与 ceilPowerOfTwo 功能互补。

js 复制代码
/**
 * @param {number} value - 待处理的数值
 * @return {number} 返回值为 "小于或等于 value 的最大 2 的幂"(例如,输入 10 时返回 8,输入 16 时返回 16)。
 */
function floorPowerOfTwo( value ) {

	return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );

}

应用场景

在 Three.js 中常用于:

  • 纹理处理:将非 2 的幂尺寸(如 100x100)转换为不超过该尺寸的最大 2 的幂(如 64x64),用于资源压缩或兼容性处理。
  • 数据结构优化:在需要按 2 的幂对齐的缓冲区或数组中,获取不超过目标长度的最大 2 的幂,避免内存浪费。
  • 算法适配:某些分治或迭代算法(如二进制搜索、金字塔层级计算)需基于 2 的幂长度,需提前转换输入。

示例

js 复制代码
console.log(floorPowerOfTwo函数(15)); // 输出: 8
console.log(floorPowerOfTwo函数(32)); // 输出: 32
console.log(floorPowerOfTwo函数(5)); // 输出: 4

setQuaternionFromProperEuler函数

用于根据内在 proper 欧拉角(Intrinsic Proper Euler Angles) 计算并设置四元数(Quaternion),是 Three.js 中处理 3D 旋转转换的核心工具函数。

js 复制代码
/**
 * @param {Quaternion} q - 待设置的四元数(用于存储计算结果)。
 * @param {number} a - 旋转角度(单位为弧度)
 * @param {number} b - 旋转角度(单位为弧度)
 * @param {number} c - 旋转角度(单位为弧度)
 * @param {('XYX'|'XZX'|'YXY'|'YZY'|'ZXZ'|'ZYZ')} order - 旋转轴顺序
 */
function setQuaternionFromProperEuler( q, a, b, c, order ) {

	const cos = Math.cos;
	const sin = Math.sin;

	const c2 = cos( b / 2 );
	const s2 = sin( b / 2 );

	const c13 = cos( ( a + c ) / 2 );
	const s13 = sin( ( a + c ) / 2 );

	const c1_3 = cos( ( a - c ) / 2 );
	const s1_3 = sin( ( a - c ) / 2 );

	const c3_1 = cos( ( c - a ) / 2 );
	const s3_1 = sin( ( c - a ) / 2 );

	switch ( order ) {

		case 'XYX':
			q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );
			break;

		case 'YZY':
			q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );
			break;

		case 'ZXZ':
			q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );
			break;

		case 'XZX':
			q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );
			break;

		case 'YXY':
			q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );
			break;

		case 'ZYZ':
			q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );
			break;

		default:
			console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );

	}

}

应用场景

  • 在 3D 物体旋转控制中,将用户输入的欧拉角(如通过 UI 滑动条设置的 XYZ 旋转角度)转换为四元数,用于更新物体的 quaternion 属性。
  • 动画系统中,将关键帧定义的欧拉角旋转转换为四元数,以便进行平滑的旋转插值(slerp)。
  • 物理引擎中,将欧拉角表示的旋转状态转换为四元数,提高旋转计算效率。

例如,若需将 "先绕 X 轴转 a 弧度,再绕 Y 轴转 b 弧度,最后绕 X 轴转 c 弧度" 的旋转转换为四元数,可调用 setQuaternionFromProperEuler(q, a, b, c, 'XYX')

关键细节

  • 内在旋转 vs 外在旋转:此处处理的是 "内在旋转"(绕物体自身坐标系轴旋转),与 "外在旋转"(绕固定世界坐标系轴旋转)的转换公式不同。
  • Proper 欧拉角特性:旋转轴顺序必须满足 "首轴 = 尾轴"(如 XYX、YZY),即第一次和第三次旋转围绕同一轴,这是 proper 欧拉角的定义。
  • 避免万向锁:四元数相比欧拉角的优势是无万向锁问题,因此该函数常用于将用户输入的欧拉角(易理解)转换为四元数(适合计算)。
  • 轴顺序影响结果:不同 order 对应的旋转效果完全不同,必须与欧拉角定义的旋转顺序一致,否则会导致旋转错误。

denormalize函数

用于将类型化数组(TypedArray)中的数值转换为标准化的浮点数(通常在 [0, 1] 或 [-1, 1] 范围),是 Three.js 中处理数据类型转换的工具函数。

js 复制代码
/**
 * @param {number} value - 类型化数组中的原始数值(如 Uint8Array 中的 0-255 整数)。
 * @param {TypedArray} array - 类型化数组实例(如 Uint8Array、Int16Array 等),用于确定 value 的数据类型。
 * @return {number} 转换后的浮点数,根据数组类型不同,范围通常为 [0, 1](无符号类型)或 [-1, 1](有符号类型)。
 */
function denormalize( value, array ) {

	switch ( array.constructor ) {

		case Float32Array:

			return value;

		case Uint32Array:

			return value / 4294967295.0;

		case Uint16Array:

			return value / 65535.0;

		case Uint8Array:

			return value / 255.0;

		case Int32Array:

			return Math.max( value / 2147483647.0, - 1.0 );

		case Int16Array:

			return Math.max( value / 32767.0, - 1.0 );

		case Int8Array:

			return Math.max( value / 127.0, - 1.0 );

		default:

			throw new Error( 'Invalid component type.' );

	}

}

应用场景

在 Three.js 中常用于:

  • 纹理数据处理:将纹理像素的原始整数数据(如 Uint8Array 存储的 RGB 值)转换为 shader 所需的 [0, 1] 浮点数。
  • 缓冲区数据解析:从类型化数组(如顶点属性的 Int16Array 数据)中读取数值并转换为标准化浮点数,用于计算或显示。
  • 数据格式转换:在不同数据格式(如 Uint8Float32)之间转换时,保持数值的相对比例。

示例

  • value = 128 arrayUint8Array,则 denormalize(128, new Uint8Array()) 返回 128/255 ≈ 0.50196
  • value = -64arrayInt8Array,则返回 -64/127 ≈ -0.5039(在 [-1, 1] 范围内)。

normalize函数

用于将 [0, 1] 范围内的浮点数 转换为 对应类型化数组(TypedArray)的数值,是 Three.js 中处理数据类型转换的核心工具函数,与 denormalize 函数互为逆操作。

js 复制代码
/**
 * @param {number} value - 待转换的浮点数,范围需在 [0, 1] 之间(通常是经过 denormalize 处理后的结果)。
 * @param {TypedArray} array - 类型化数组实例(如 Uint8Array、Int16Array 等),用于指定目标数据类型。
 * @return {number} 转换后的数值,类型与 array 一致(如 Uint8 类型的整数、Int32 类型的整数等)。
 */
function normalize( value, array ) {

	switch ( array.constructor ) {

		case Float32Array:

			return value;

		case Uint32Array:

			return Math.round( value * 4294967295.0 );

		case Uint16Array:

			return Math.round( value * 65535.0 );

		case Uint8Array:

			return Math.round( value * 255.0 );

		case Int32Array:

			return Math.round( value * 2147483647.0 );

		case Int16Array:

			return Math.round( value * 32767.0 );

		case Int8Array:

			return Math.round( value * 127.0 );

		default:

			throw new Error( 'Invalid component type.' );

	}

}

应用场景

在 Three.js 中常用于:

  • 纹理数据编码:将 shader 输出的 [0, 1] 浮点颜色值转换为 Uint8Array 等类型化数组的整数像素值(如 RGB 分量),用于存储或传输。
  • 缓冲区数据写入:将计算得到的浮点数(如顶点属性、法向量)转换为类型化数组的整数格式,减少内存占用或适配硬件要求。
  • 数据格式转换:在浮点数与整数类型化数组之间转换时,保持数值的相对比例(如将 0.3 转换为 Uint8 类型的 77,即 0.3×255≈76.5 四舍五入)。

例如:

  • value=0.3arrayUint8Array,则 normalize(0.3, new Uint8Array()) 返回 770.3×255=76.5 四舍五入)。
  • value=0.8arrayInt16Array,则返回 262140.8×32767=26213.6 四舍五入)。
相关推荐
ts码农5 分钟前
model层实现:
java·服务器·前端
修仙的人10 分钟前
【开发环境】 VSCode 快速搭建 Python 项目开发环境
前端·后端·python
泡芙牛牛13 分钟前
CSS动画:animation、transition、transform、translate的区别
前端·css
shenyi15 分钟前
openlayers实现高德地图区划+撒点+点击
前端
wwy_frontend15 分钟前
不想装 Redux?useContext + useReducer 就够了!
前端·react.js
前端老鹰25 分钟前
HTML <link rel="preload">:提前加载关键资源的性能优化利器
前端·性能优化·html
兰为鹏28 分钟前
react-quill使用服务端上传图片handlers导致中文输入问题-原理分析
前端
FanetheDivine31 分钟前
具有配置项和取消能力的防抖节流函数
前端·javascript
卸任36 分钟前
Docker打包并部署Next.js
前端·docker·next.js
行星飞行36 分钟前
使用 Figma mcp 和 Playwright mcp 提升 UI 开发与调试效率,附 rule 分享
前端