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

