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

如何优化raycast射线检测精度 实现精准拾取视线目标物体

检测精度差的核心原因

你当前直接使用Physics.SphereCast的返回结果作为拾取目标,本身就存在逻辑缺陷:

  • 球形检测会覆盖半径范围内所有碰撞体,默认返回的是最先与球体产生接触的物体,而非视线正中心对准的物体,当多个可拾取物摆放密集时,旁边物体的碰撞体只要先蹭到检测球,就会被误判为目标
  • 射线起点计算错误:ScreenToWorldPoint传入z值为0时,返回的点与相机处于同一Z平面,起点位于相机内部,容易误触发相机挂载的碰撞体
  • 未对多命中结果做筛选,直接取第一个命中值,没有优先匹配视线中心的目标
调整方案
  • 优先使用无半径的中心射线做精确检测,仅当精确射线无命中时,用极小半径的球形射线做容错,避免玩家瞄得略有偏差就完全无法拾取
  • 所有检测使用All系列接口拿到全部命中结果,遍历计算每个命中碰撞体到中心视线的垂直距离,选择距离最近的物体作为最终拾取目标,而非直接取距离相机最近的命中
  • 将球形检测的半径压缩到0.050.1游戏单位(对应现实中510厘米),半径越大误判概率越高
  • 修正射线起点逻辑,直接从相机近裁剪面的正中心发射射线,避免起点位置错误
修正后的参考代码
// 球形检测仅做容错,半径设为极小值
private float sphereCastRadius = 0.07f;
private float maxPickupDistance = 3f;
private int interactableLayer = 1 << interactableLayerIndex;

void Update()
{
    lookObject = null;
    // 直接生成从相机近裁剪面中心出发、沿视线向前的中心射线,无需手动计算屏幕坐标
    Ray centerSightRay = mainCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f));
    RaycastHit[] hitResults;
    RaycastHit bestMatchHit = default;
    float minDistanceToSight = float.MaxValue;

    // 第一步:发射无半径精确射线,检测视线正中心的目标
    hitResults = Physics.RaycastAll(centerSightRay, maxPickupDistance, interactableLayer);
    // 精确射线无命中时,再用极小半径球形射线做容错检测
    if (hitResults.Length == 0)
    {
        hitResults = Physics.SphereCastAll(centerSightRay, sphereCastRadius, maxPickupDistance, interactableLayer);
    }

    // 遍历所有命中结果,筛选离视线中心最近的物体
    foreach (RaycastHit hit in hitResults)
    {
        // 跳过触发器碰撞体
        if (hit.collider.isTrigger) continue;
        // 计算当前碰撞体上离视线最近的点,与视线的垂直距离
        Vector3 closestPointOnCollider = hit.collider.ClosestPoint(centerSightRay.GetPoint(hit.distance));
        float distanceToCenterSight = Vector3.Distance(closestPointOnCollider, centerSightRay.GetPoint(hit.distance));
        // 记录距离视线最近的命中
        if (distanceToCenterSight < minDistanceToSight)
        {
            minDistanceToSight = distanceToCenterSight;
            bestMatchHit = hit;
        }
    }

    if (bestMatchHit.collider != null)
    {
        lookObject = bestMatchHit.collider.gameObject;
    }

    // 原有拾取逻辑保留
    if (PickingUp)
    {
        if (currentlyPickedUpObject == null)
        {
            if (lookObject != null)
            {
                PickupObject();
                if (lookObject.CompareTag("TargetObj") && !targetObjectsList.Contains(lookObject.gameObject))
                {
                    if (aSource)
                    {
                        aSource.Play();
                    }
                    targetObjectsList.Add(lookObject.gameObject); 
                    if (targetObjectsList.Count == targetObjects.Length)
                    {
                        // 原有目标集齐逻辑
                    }
                }
                CenterIcon.SetActive(false);
            }
        }
        else
        {
            BreakConnection();
        }
    }
}
额外优化建议
  • 调整可拾取物体的碰撞体尺寸,不要让碰撞体远大于物体模型本身,过大的碰撞体是密集场景误判的常见原因
  • 增加拾取目标高亮反馈:当检测到当前注视的可拾取物时,给物体加高亮描边,玩家点击前就能确认系统识别的目标是否正确,降低误拾取的感知

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:54:23