You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Three.js r109 无鼠标场景下如何检测X、Z坐标是否与水面网格相交而非地形网格

场景适配的最优检测方案选择

针对你当前固定水位、预生成SimplexNoise地形的开发场景,基于高度的预存判定是远优于Raycaster的实现方案

  • 方案核心逻辑:你当前场景的两个关键参考面是高度固定、可提前遍历计算的,完全不需要运行时做射线求交:
    • 水面是覆盖全图的固定高度平面(挂载在Reflector下的半透明平面),Y坐标是全局固定值(比如waterLevel = 0),不存在动态起伏的话没有任何计算开销
    • 地形是SimplexNoise生成的高度图,在你生成地形网格的阶段已经遍历计算过所有(X,Z)位置的对应地形高度,直接把这些值存到全局的二维高度数组里即可
  • 检测逻辑完全为O(1)时间复杂度:
    1. 对任意待判定的(X,Z)坐标,直接从预存高度数组中取出对应位置的地形高度terrainHeight
    2. 对比固定水面高度值:若terrainHeight < waterLevel,该位置即为有效水面生成点,反之则为陆地
    3. 这种方案的性能可以支撑你每秒做十万级以上的坐标判定,完全适配随机选点、反复重试直到找到合法水面位置的生成逻辑,不会出现任何卡顿
  • 后续兼容性:如果需要做动态涨潮、波浪水面的玩法,只要同步更新全局高度数组的数值即可,不需要替换整套检测逻辑,比维护射线检测的代码可维护性高很多
动态场景下的Raycaster实现方案

如果后续需要做动态起伏的波浪水面、无法预存全量高度值的场景,再启用Raycaster做垂直定向检测(完全规避鼠标拾取的交互逻辑):

  • 核心检测思路:从待测(X,Z)坐标的正上方(高于地图最高地形的位置)发射一条垂直向下的射线,分别计算射线和地形网格、水面网格的交点,哪个交点距离射线起点更近,哪个就是该坐标位置的实际地表/水面
  • 参考实现代码(适配r109版本):
// 全局单例初始化,不要反复新建
const globalRaycaster = new THREE.Raycaster();
const rayStartPoint = new THREE.Vector3();
const rayDownDir = new THREE.Vector3(0, -1, 0); // 垂直向下固定方向

// 提前缓存两个需要检测的网格引用,避免遍历全场景
const terrainMesh = 你的地形网格对象;
const waterMesh = 你挂载在Reflector上的可视半透明水面网格;

function isCoordinateOnWater(x, z) {
  // 重置射线起点到待测点正上方
  rayStartPoint.set(x, 1000, z);
  globalRaycaster.set(rayStartPoint, rayDownDir);
  // 设置射线最大检测距离,覆盖全图高低差范围即可
  globalRaycaster.far = 2000;

  // 分别检测两个网格的交点
  const terrainIntersects = globalRaycaster.intersectObject(terrainMesh, false);
  const waterIntersects = globalRaycaster.intersectObject(waterMesh, false);

  const firstTerrainY = terrainIntersects[0]?.point.y ?? -Infinity;
  const firstWaterY = waterIntersects[0]?.point.y ?? Infinity;

  // Y值更大的交点更靠近射线起点,也就是实际接触的面
  return firstWaterY > firstTerrainY;
}
  • 针对r109版本的避坑提示:
    • 不要把Reflector内部的离屏渲染目标、缓存几何体加入检测数组,只取你自己创建的、面向相机的半透明水面网格做检测
    • 检测时不要传入整个场景作为检测对象,只单独传入地形、水面两个目标网格,避免树木、建筑等其他模型干扰检测结果、增加不必要的遍历开销
Raycaster的实例复用原则

整个游戏全局仅创建1个Raycaster单例即可,绝对不要为每个检测逻辑新建独立实例

  • Raycaster是无状态的工具类,每次调用检测方法时都会重置内部的临时计算变量,不存在实例间的状态干扰
  • 反复新建Raycaster会触发频繁的对象初始化、垃圾回收,反而会导致随机卡顿,复用单例的内存开销几乎为零,性能比新建实例高2-3个数量级

内容的提问来源于stack exchange,提问作者NikDaOverlord

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.30 04:57:04