我想设计一个模拟仿真雨 雪与激光雷达交互的方案,需要激光雷达被雨 雪阻挡的点云数据,有什么技术方案可以供我研究或参考吗?一般雨 雪的实现都是使用niagara粒子,而激光雷达是以raycast,他们之间是否可以进行碰撞检测?
可以碰撞,但要分清两件事:Niagara 粒子默认是 GPU 模拟,激光雷达的 raycast(Line Trace)是 CPU 端的物理查询,两者彼此看不到。
思路有几种:
- 最简单:不用粒子做命中,而是在雷达采样时,对每条射线额外按概率判定"被雨雪遮挡"。概率可以用降雨强度、射线长度(Beer-Lambert:P=1-exp(-k·距离))计算,命中后把点云替换成雨滴/雪花的近距离点或直接丢弃。这样不需要真实碰撞,性能好,也容易调参。
- 想要空间上真实:用 Niagara 的 CPU 粒子并开启碰撞事件,或者把粒子位置写进 Data Interface(Niagara Data Channel 可以把数据传回 Blueprint/C++),再在雷达里对这些粒子做球体相交判断。
- GPU 粒子可以用深度/场景缓冲做近似,但读回 CPU 有延迟。
如果是自动驾驶仿真,可以参考 CARLA 或 AirSim 里雷达的天气噪声模型。另外 UE 里的 Line Trace 记得用专用 Trace Channel,避免命中粒子的无关碰撞体。
谢谢提供思路方案。
1、是不是基于强度、衰减率和概率的计算方式?carla官方的方案?感觉不太符合需求或者说有点假
2、基于空间的与需求最合理,目前雨雪是用cpu粒子,且目前已实现写进datainsterface 位置读回方案。对于cpu粒子开启碰撞事件与linetrace交互好像没实现。
3、看起来技术难度好高
补充一下,你已经把 CPU 粒子位置通过 Niagara Data Interface 读回来了,那最难的一步其实已经做完了。Line Trace 本身确实不会命中粒子(粒子没有物理体,CPU 粒子的 Collision 模块只是粒子自己和场景碰撞,也不会让射线看到它们),所以不要去想"让射线打到粒子",而是自己在雷达采样里做射线–球体相交:
- 每帧把读回的粒子位置存成 TArray,雨滴/雪花当作半径 r 的小球(r 取视觉大小的几倍,比如 1–3 cm,射线很细,半径太小几乎永远打不中,可以当作可调的"等效截面"参数)。
- 对每条射线(起点 O,单位方向 D,最大距离 L),先做普通 LineTrace 得到墙/地面命中距离 T,然后只在 [0, min(T, L)] 里找最近的粒子命中:
t = dot(P - O, D);如果 t < 0 或 t > min(T, L) 跳过;
dist² = |P - O|² - t²;如果 dist² <= r²,命中,距离 t - sqrt(r² - dist²),取所有粒子里最小的 t。
命中了就把这个点替换成粒子命中点(可以再把强度调低)。 - 性能:粒子数几千以上、射线几万条,暴力 O(N×M) 会爆。做法是先把粒子放进均匀网格(格子边长 ≈ 1–2 m 的哈希,TMap<FIntVector, TArray>),每条射线沿网格走(3D DDA),或者更省事:先按雷达的有效范围裁掉粒子(只保留雷达锥体内的),再用 ParallelFor 并行处理射线。雨雪生成区域本来就只会跟着雷达附近生成的话,粒子总量也能压在几千个以内。
- 如果粒子是整片天空区域,远处的可以用我之前说的概率衰减做补充:近场(比如 0–30 m)用真实粒子相交,远场用 Beer-Lambert 概率,两者混合,数据看起来不会假,计算量也可控。
另外 CPU 粒子开碰撞事件那条路我也不推荐:事件是粒子打到场景几何体时触发的,跟雷达射线没关系,你现在这个"读回位置 + 自己做相交"就是对的方向,难度其实没有看上去那么高,核心代码就上面那十几行。