normalize() 的作用(以及 Three.js raycasting 为何需要它)

发布: (2026年2月13日 GMT+8 00:26)
3 分钟阅读
原文: Dev.to

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 的 nearfar 属性:

raycaster.near = 0;
raycaster.far  = 100; // 限制到 100 个世界单位

保持方向向量已归一化,让 raycaster 处理距离限制。

形象类比

把方向向量想象成指南针的指针。

  • 归一化前:一支 10 米长的箭。
  • 归一化后:一支 1 米长、指向相同方向的箭。

Three.js 的射线投射期望使用 1 米长的版本,这样所有距离计算才能保持简洁且可预测。

0 浏览
Back to Blog

相关文章

阅读更多 »

疯狂的 React key

通过 map 渲染 tsx export function Parent { const array, setArray = useState1, 2, 3, 4, 5; useEffect => { setTimeout => { setArrayprev => 6, 7, 8, 9, 10, ...prev;...