获取相机视口内物体在视线范围内某点的方法


  我们在做HUD时经常使用物体的位置作为世界坐标点, 这在小物体的情况下没有问题, 但是在对于大型物体就有点麻烦, 因为我们的视角不一定能看到该点, 

比如大楼, 大桥甚至公路等, 希望能在物体进入视线范围内时获取一个当前视线范围内该物体离屏幕中心最近的一个点, 作为HUD的世界坐标点来显示.

  1. 首先需要测试物体是否在可视范围内, 一般使用 OnBecameVisible() 生命周期即可.

  2. 获取可视范围内离屏幕中心最近的点, 这个可以是多边形面上某点, 不一定是多边形的点.

  3. 因为视角是个三角形, 所以非规则物体经常是离相机最近的点不在相机视角之内.

  4. 不能做的太复杂

 

  于是我们从生命周期开始做, 在进入相机视角时添加到某个列表中, 因为依赖于Collider的API 并且需求该Collider为凸多边形, 所以对MeshCollider进行判断

    private void OnBecameVisible()
    {
        var collider = GetComponent<Collider>();
        if(collider)
        {
            var mc = collider as MeshCollider;
            if(mc && mc.convex == false)
            {
                return;
            }
            visibleColliders.Add(collider);
        }
    }

  然后因为相机是移动的, 计算位置也需要Update

    public static IEnumerator Run()
    {
        while(true)
        {
            if(visibleColliders.Count > 0)
            {
                foreach(var visibleCollider in visibleColliders)
                {
                    var nearestPoint = visibleCollider.ClosestPoint(GetCameraViewPoint(visibleCollider));
                    onVisible.Invoke(visibleCollider, nearestPoint);
                }
            }
            yield return null;
        }
    }

  关键就是计算离屏幕中心最近的位置了, 因为屏幕中心可以做一条射线出去, 这就是屏幕中心的线段, 按照理论 : 不一定有一个顶点一定会在屏幕视线范围内.

这个比较好理解吧, 一个面经过相机视线, 可是所有点都不在相机视线范围内, 所以简单数学方法获取离线段最近的点没有意义.

  这里就用Collider自带的API来计算一个大概的值即可:

    private static Vector3 GetCameraViewPoint(Collider target)
    {
        var dis = (Camera.main.transform.position - target.bounds.center).magnitude;
        var pos = Camera.main.transform.position + Camera.main.transform.forward * dis;
        return pos;
    }

  这里使用相机到物体的中心位置的距离作为参考, 从相机发射的射线在这个距离的点进行计算, 然后计算该点到物体的最近位置, 所得到的位置就作为HUD世界坐标, 

在大部分情况下是符合逻辑的...

 


作者:tiancaiKG,发布于:2019/05/16
原文:https://www.cnblogs.com/tiancaiwrk/p/10872051.html