Unity中保持射线水平沿物体表面发射Raycast的实现问题求助
任意旋转容器表面射线发射与液面网格生成修复方案
你之前的方案失效核心原因是强制将射线方向的Y分量置0,本质是把物体自身的局部轴向强行投影到世界空间XZ平面,完全丢失了物体多轴旋转带来的倾斜信息,最终射线方向和实际物体表面方向不符。
具体修复实现逻辑如下:
- 先获取采样点对应物体表面的世界空间法向量:如果是通过预发射射线得到的采样点,可以直接读取
RaycastHit.normal属性;如果是规则基础碰撞体的固定点采样,可先计算局部空间的表面法向量,再调用transform.TransformDirection()转换为世界空间法向量,完全保留物体的旋转信息。 - 计算贴合表面的射线发射切向量:不需要手动修改任何向量分量,直接使用Unity内置的
Vector3.OrthoNormalize()方法,输入表面法向量和任意不共线参考向量,即可得到两个正交的、完全贴合当前表面的切向量,该计算结果不受物体旋转角度影响。 - 射线发射防误触处理:射线起点从表面采样点沿法向量向外偏移极小值(推荐
0.001f ~ 0.01f),避免射线和当前物体自身碰撞体产生误检测。
示例实现代码:
// 假设hit为提前采样得到的物体表面RaycastHit结果 Vector3 surfaceNormal = hit.normal; Vector3 surfaceTangent, surfaceBitangent; // 避免法向量和参考向量共线导致计算失败 if (Mathf.Abs(Vector3.Dot(surfaceNormal, Vector3.up)) < 0.999f) { Vector3.OrthoNormalize(ref surfaceNormal, ref Vector3.up, out surfaceTangent, out surfaceBitangent); } else { Vector3.OrthoNormalize(ref surfaceNormal, ref Vector3.right, out surfaceTangent, out surfaceBitangent); } // 发射沿表面延伸的射线 Ray surfaceRay = new Ray(hit.point + surfaceNormal * 0.005f, surfaceTangent); if (Physics.Raycast(surfaceRay, out RaycastHit surfaceHit, 2f)) { // 此处处理表面射线的击中结果,用于液面网格顶点采样 }
针对自定义拼接容器的液面生成需求,你可以在完成全表面采样后,对所有采样点的高度值做平面拟合校验,过滤容器拼接缝隙产生的异常采样值,最终生成的液面网格会更平滑稳定。
内容的提问来源于stack exchange,提问作者Tim Starmer
相关产品推荐
相关产品推荐

