normalize() 的作用(以及 Three.js raycasting 为何需要它)
Source: Dev.to
normalize() 的作用
normalize() 会让向量的长度恰好为 1 单位,同时保持其方向不变。
const rayDirection = new THREE.Vector3(10, 0, 0); // 长度 = 10
rayDirection.normalize(); // → (1, 0, 0)
在数学上,归一化是把向量除以它的长度:
[ \text{normalized} = \frac{v}{|v|} ]
const v = new THREE.Vector3(10, 0, 0);
console.log(v.length()); // 10
v.normalize();
console.log(v.length()); // 1
方向保持不变,只有大小(模)改变。
为什么 Three.js 的射线投射需要归一化的方向
距离计算假设单位长度
当射线击中某物体时,Three.js 会计算交点在射线上的距离。这些距离值只有在方向向量长度为 1 时才有意义。如果方向向量的长度是 10,内部计算会把所有东西错误地放大,距离将不再对应世界单位。
交点公式假设单位向量
许多射线‑几何交点公式(以及 Three.js 文档)都要求方向向量是单位向量。省略归一化会导致未定义行为,即使有时看起来还能工作。
正确使用 normalize() 的方式
常见的射线投射设置
const rayOrigin = new THREE.Vector3(-3, 0, 0);
const rayDirection = new THREE.Vector3(10, 0, 0);
rayDirection.normalize(); // 确保长度为 1
const raycaster = new THREE.Raycaster(rayOrigin, rayDirection);
- Origin(起点): 位于
x = -3 - Direction(方向): 沿 X 轴向右指向,已归一化
调用:
raycaster.intersectObjects(scene.children);
将返回正确且一致的交点距离。
保留原始向量(如有需要)
const original = new THREE.Vector3(10, 0, 0);
const direction = original.clone().normalize(); // original 保持不变
控制射线的范围
不要通过缩放方向向量来限制范围。应当设置 raycaster 的 near 和 far 属性:
raycaster.near = 0;
raycaster.far = 100; // 限制到 100 个世界单位
保持方向向量已归一化,让 raycaster 处理距离限制。
形象类比
把方向向量想象成指南针的指针。
- 归一化前:一支 10 米长的箭。
- 归一化后:一支 1 米长、指向相同方向的箭。
Three.js 的射线投射期望使用 1 米长的版本,这样所有距离计算才能保持简洁且可预测。