【问题标题】:Draw bounding rectangle (screen space) around a game object with a renderer (world space) (Unity)使用渲染器(世界空间)在游戏对象周围绘制边界矩形(屏幕空间)(Unity)
【发布时间】:2020-12-23 00:36:00
【问题描述】:

我有一个游戏对象,它存在于我的场景中的世界空间中。我想获取此游戏对象的渲染器在屏幕空间中的边界矩形角的坐标,因为我有想要定位在此框周围的 UI 元素。

背景:我正在制作一个教程,我正在使用面板来使所有内容变暗,除了一个不会变暗的游戏对象。我可以使用已经存在于屏幕空间中并对其进行矩形变换的按钮轻松完成此操作,但我无法弄清楚如何围绕世界空间中的游戏对象执行此操作。我们正在使用带有正交投影的相机并且正在使用 Unity 版本 2019.2.17f1。

这是我尝试过的:

public void FocusOnRenderer(Renderer renderer) {

        // left, top, right, and bottom are Panels whose pivots are set as follows:
        // top: (1, 0)
        // right: (0, 0)
        // bottom: (0, 1)
        // left: (1, 1)
        // so when their positions are set to be the corners of the target bounding box, they will fit together nicely.

        left.gameObject.SetActive(true);
        top.gameObject.SetActive(true);
        right.gameObject.SetActive(true);
        bottom.gameObject.SetActive(true);

        Vector3 center = HandleUtility.WorldToGUIPoint(renderer.bounds.center); // center of bounding box
        Vector3 halfSize = HandleUtility.WorldToGUIPoint(renderer.bounds.extents)); // half size of bounding box

        Vector3 topRight = center + halfSize;
        Vector3 topLeft = center  + new Vector3(-halfSize.x, halfSize.y, halfSize.z);
        Vector3 bottomRight = center  + new Vector3(halfSize.x, -halfSize.y, halfSize.z);
        Vector3 bottomLeft = center  + new Vector3(-halfSize.x, -halfSize.y, halfSize.z);

        left.position = topLeft;
        top.position = topRight;
        right.position = bottomRight;
        bottom.position = bottomLeft;
    }

我认为这是错误的,因为我正在使用渲染器的边界来计算 halfSize 和 center 并没有给我一个边界矩形。我希望有一种简单的内置方法可以做到这一点,但到目前为止我还没有找到任何东西。

感谢您的帮助!

【问题讨论】:

  • 您是否尝试过使用 Vector2 而不是 Vector3? WorldToGUIPoint() 返回一个 Vector2,所以在类型转换过程中可能会发生一些事情
  • @Kirlian 在这种情况下,所发生的只是z 组件将是0
  • @derHugo 这不是我们想要的,因为我们在谈论 UI 吗?无论如何,它们将是0,因为halfSize 来自Vector2 方法,并且它将自己的z 设置为0
  • @Kirlian 好吧,是的...我只是提到了您的评论something may be happening during the type conversion -> 不,在类型转换期间没有什么特别的事情发生,除了z 将是0 .. 它是要记住的事情不是真正“发生”的事情;)
  • @derHugo 哦,对不起,我误会了

标签: c# unity3d unity-ui


【解决方案1】:

我找到了答案(来自 Unity 论坛上@SparrowsNest 的视频建议)!这是从相关时间戳开始的视频:https://youtu.be/2Tgqr1_ajqE?t=1061

步骤:

  1. 从渲染器的边界获取边界框的角
  2. 将这些角转换为屏幕空间
  3. 获取最小和最大 x 和 y 值
  4. 使用这些最小和最大 x 和 y 值设置面板的位置

这是我的代码:

    public void FocusOnBounds(Bounds bounds) {
        
        // left, top, right, and bottom are Panels whose pivots are set as follows:
        // top: (1, 0)
        // right: (0, 0)
        // bottom: (0, 1)
        // left: (1, 1)
        // so when their positions are set to be the corners of the target bounding box, they will fit together nicely.

        left.gameObject.SetActive(true);
        top.gameObject.SetActive(true);
        right.gameObject.SetActive(true);
        bottom.gameObject.SetActive(true);

        Vector3 c = bounds.center;
        Vector3 e = bounds.extents;

        Vector3[] worldCorners = new [] {
            new Vector3( c.x + e.x, c.y + e.y, c.z + e.z ),
            new Vector3( c.x + e.x, c.y + e.y, c.z - e.z ),
            new Vector3( c.x + e.x, c.y - e.y, c.z + e.z ),
            new Vector3( c.x + e.x, c.y - e.y, c.z - e.z ),
            new Vector3( c.x - e.x, c.y + e.y, c.z + e.z ),
            new Vector3( c.x - e.x, c.y + e.y, c.z - e.z ),
            new Vector3( c.x - e.x, c.y - e.y, c.z + e.z ),
            new Vector3( c.x - e.x, c.y - e.y, c.z - e.z ),
        };

        IEnumerable<Vector3> screenCorners = worldCorners.Select(corner => Camera.main.WorldToScreenPoint(corner));
        float maxX = screenCorners.Max(corner => corner.x);
        float minX = screenCorners.Min(corner => corner.x);
        float maxY = screenCorners.Max(corner => corner.y);
        float minY = screenCorners.Min(corner => corner.y);

        Vector3 topRight = new Vector3(maxX, maxY, 0);
        Vector3 topLeft = new Vector3(minX, maxY, 0);
        Vector3 bottomRight = new Vector3(maxX, minY, 0);
        Vector3 bottomLeft = new Vector3(minX, minY, 0);

        left.position = topLeft;
        top.position = topRight;
        right.position = bottomRight;
        bottom.position = bottomLeft;
    }

【讨论】:

    【解决方案2】:

    如果上面的代码不起作用,下面是从

    中提取的代码

    http://quill18.com/unity_tutorials/unit_selection/

    函数输入:任何呈现在屏幕上的可见。

    输出:可在画布中使用的 2D 矩形边界

    static Rect RendererBoundsInScreenSpace(Renderer r) {
            // This is the space occupied by the object's visuals
            // in WORLD space.
            Bounds bigBounds = r.bounds;
    
            if(screenSpaceCorners == null)
                screenSpaceCorners = new Vector3[8];
    
            Camera theCamera = Camera.main;
    
            // For each of the 8 corners of our renderer's world space bounding box,
            // convert those corners into screen space.
            screenSpaceCorners[0] = theCamera.WorldToScreenPoint( new Vector3( bigBounds.center.x + bigBounds.extents.x, bigBounds.center.y + bigBounds.extents.y, bigBounds.center.z + bigBounds.extents.z ) );
            screenSpaceCorners[1] = theCamera.WorldToScreenPoint( new Vector3( bigBounds.center.x + bigBounds.extents.x, bigBounds.center.y + bigBounds.extents.y, bigBounds.center.z - bigBounds.extents.z ) );
            screenSpaceCorners[2] = theCamera.WorldToScreenPoint( new Vector3( bigBounds.center.x + bigBounds.extents.x, bigBounds.center.y - bigBounds.extents.y, bigBounds.center.z + bigBounds.extents.z ) );
            screenSpaceCorners[3] = theCamera.WorldToScreenPoint( new Vector3( bigBounds.center.x + bigBounds.extents.x, bigBounds.center.y - bigBounds.extents.y, bigBounds.center.z - bigBounds.extents.z ) );
            screenSpaceCorners[4] = theCamera.WorldToScreenPoint( new Vector3( bigBounds.center.x - bigBounds.extents.x, bigBounds.center.y + bigBounds.extents.y, bigBounds.center.z + bigBounds.extents.z ) );
            screenSpaceCorners[5] = theCamera.WorldToScreenPoint( new Vector3( bigBounds.center.x - bigBounds.extents.x, bigBounds.center.y + bigBounds.extents.y, bigBounds.center.z - bigBounds.extents.z ) );
            screenSpaceCorners[6] = theCamera.WorldToScreenPoint( new Vector3( bigBounds.center.x - bigBounds.extents.x, bigBounds.center.y - bigBounds.extents.y, bigBounds.center.z + bigBounds.extents.z ) );
            screenSpaceCorners[7] = theCamera.WorldToScreenPoint( new Vector3( bigBounds.center.x - bigBounds.extents.x, bigBounds.center.y - bigBounds.extents.y, bigBounds.center.z - bigBounds.extents.z ) );
    
            // Now find the min/max X & Y of these screen space corners.
            float min_x = screenSpaceCorners[0].x;
            float min_y = screenSpaceCorners[0].y;
            float max_x = screenSpaceCorners[0].x;
            float max_y = screenSpaceCorners[0].y;
    
            for (int i = 1; i < 8; i++) {
                if(screenSpaceCorners[i].x < min_x) {
                    min_x = screenSpaceCorners[i].x;
                }
                if(screenSpaceCorners[i].y < min_y) {
                    min_y = screenSpaceCorners[i].y;
                }
                if(screenSpaceCorners[i].x > max_x) {
                    max_x = screenSpaceCorners[i].x;
                }
                if(screenSpaceCorners[i].y > max_y) {
                    max_y = screenSpaceCorners[i].y;
                }
            }
    
            return Rect.MinMaxRect( min_x, min_y, max_x, max_y );
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-14
      • 1970-01-01
      • 2020-08-04
      相关资源
      最近更新 更多