范围判断-射线穿透遇到的问题及解决方案

本文针对坐标点是否位于多边形内的判断问题,介绍了正确的多边形顶点排序方法及其对射线穿透算法的影响。强调了点顺序的重要性,并通过实例说明如何确保算法准确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

工作需要判断某个坐标点是否在一系列点所围成的多边形内,使用MOFEI_BIQIGU博主的射线穿透算法,发现一些情况下明明坐标就在范围内,但检测方法的判断结果是false,网上也找不到同样提问或者解答。水平有限浅学一点博主皮毛后,发现坐标点的顺序会影响判断结果,在这里补充下围点的条件:围点列表中相邻项必须按照多边形相邻点来放置,顺时针/逆时针均可。

举个例子,受测点t(6,3),需要判断是否位于a(5,2)、b(8,2)、c(5,4)、d(8,4)所形成的多边形中,如图所示,结果是true:

根据博主的算法, 使用pointList中的顺序,将相邻两点的连接,再检测射线是否穿透该点。但如果pointList相邻两点不是围点,则该线段不应用于检测射线穿透。射线应该与围点所形成的多边形的边线相检测是否相交。

 

证明方式:根据图1,若pointList的顺序为a、b、c、d的错误顺序(b、c不是相邻点),则算法判断结果为false,与实际不符:

 正确检测方式,调用前必须对pointList正确排序,例如使用a、b、d、c的逆时针围点排序,再进行调用,则相连线均为边线,方法执行结果正确:

 

### Unity 中解决 UI 穿透事件的方法 在 Unity 开发中,UI 的穿透事件是一个常见的问题。当 Canvas 后面的对象绑定了碰撞器或触发器时,可能会发生点击事件穿过 UI 并触碰到背景对象的情况。以下是几种有效的解决方案: #### 使用 `EventSystem` 和 `GraphicRaycaster` 通过 `EventSystem` 和 `GraphicRaycaster` 来检测鼠标位置是否位于某个 UI 上方。如果确实如此,则可以阻止后续的游戏世界射线投射逻辑。 ```csharp void Update() { if (Input.GetMouseButtonDown(0)) { PointerEventData pointerData = new PointerEventData(EventSystem.current); pointerData.position = Input.mousePosition; List<RaycastResult> results = new List<RaycastResult>(); EventSystem.current.RaycastAll(pointerData, results); foreach (var result in results) { if (result.gameObject.layer == LayerMask.NameToLayer("UI")) { Debug.Log($"Clicked on UI: {result.gameObject.name}"); HandleUIClick(result.gameObject); // 处理UI点击 return; } } HandleGameWorldClick(); // 如果未点击到UI则处理游戏世界的点击 } } ``` 此方法利用了 `PointerEventData` 和 `RaycastAll` 函数来精确判断当前鼠标位置是否有任何 UI 对象被覆盖[^1]。 --- #### 设置 Raycast Target 属性 对于不需要接收点击事件的 UI 组件,可以通过设置其 `Raycast Target` 属性为 false 来禁用它们参与射线检测。这样即使这些 UI 存在于场景中也不会阻挡或者干扰其他对象的交互行为。 --- #### 添加 Blocking GameObjects 为了防止特定区域内的所有输入传递给底层物体,可以在该区域内放置一个透明的 Panel,并将其 `Interactable` 设定为 true。这个面板会拦截所有的触摸/鼠标操作而不允许继续向下传播至更深层次的内容[^2]。 --- #### 调整摄像机 Culling Mask 另一种方式是调整 Camera 的 culling mask 排除掉那些不希望接受用户互动层面上的东西(比如 Background Layers)。这能有效减少不必要的冲突同时也提高了性能表现因为减少了需要考虑渲染及物理运算的部分数量。 --- #### 特殊情况下的多屏支持优化 针对多显示器环境中的特殊需求,例如 zfbrowser 插件遇到的问题——即不同显示屏上的坐标映射错误导致无法正常响应鼠标的移动和按键动作——我们应当重新定义一套适用于跨多个监视器布局下工作的全局坐标系转换机制。具体做法是在原有基础上增加额外一步将原始设备像素值转化为标准化单位后再做进一步计算[^3]: ```csharp private Vector2 ConvertScreenToWorldPoint(Vector2 screenPosition) { int screenWidth = Screen.width * Display.displays.Length; // 假设水平排列 float normalizedX = Mathf.Clamp(screenPosition.x / screenWidth, 0f, 1f); return Camera.main.ScreenToWorldPoint(new Vector3(normalizedX * screenWidth, screenPosition.y)); } ``` 上述代码片段展示了如何基于总宽度比例化每个独立显示单元内部相对定位从而实现统一管理的目的。 --- ### 总结 以上介绍了多种途径用于应对 Unity 工程里可能出现的各种形式的 UI 点击穿刺现象及其对应的预防措施。开发者可以根据项目实际情况灵活选用最适合自己的策略组合起来构建更加健壮可靠的人机界面体系结构。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值