【问题标题】:How can I perform clipping on rotated rectangles?如何对旋转的矩形执行剪辑?
【发布时间】:2011-02-14 21:13:51
【问题描述】:

所以我有这个面板类。它有点像一个窗口,您可以在其中调整大小、关闭、添加按钮、滑块等。如果您还记得的话,它就像 Morrowind 中的状态屏幕。我想要的行为是,当一个精灵在面板的边界之外时,它不会被绘制,如果它部分在外面,只有里面的部分会被绘制。 所以它现在要做的是首先获取一个表示面板边界的矩形,以及一个用于精灵的矩形,它找到两者之间的相交矩形,然后将该相交转换为精灵矩形的局部坐标并使用 that 为源矩形。它的工作原理和我觉得代码一样聪明,我无法摆脱这种感觉,即有更好的方法来做到这一点。此外,通过这种设置,我无法为我的 2D 相机使用全局变换矩阵,“世界”中的所有内容都必须通过相机参数进行绘制。无论如何,这是我的代码:
对于十字路口:

     public static Rectangle? Intersection(Rectangle rectangle1, Rectangle rectangle2)
     {
        if (rectangle1.Intersects(rectangle2))
        {
            if (rectangle1.Contains(rectangle2))
            {
                return rectangle2;
            }
            else if (rectangle2.Contains(rectangle1))
            {
                return rectangle1;
            }
            else
            {
                int x = Math.Max(rectangle1.Left, rectangle2.Left);
                int y = Math.Max(rectangle1.Top, rectangle2.Top);
                int height = Math.Min(rectangle1.Bottom, rectangle2.Bottom) - Math.Max(rectangle1.Top, rectangle2.Top);
                int width = Math.Min(rectangle1.Right, rectangle2.Right) - Math.Max(rectangle1.Left, rectangle2.Left);
                return new Rectangle(x, y, width, height);
            }
        }
        else
        {
            return null;
        }
     }

在面板上实际绘图:

    public void DrawOnPanel(IDraw sprite, SpriteBatch spriteBatch)
    {
        Rectangle panelRectangle = new Rectangle(
           (int)_position.X,
           (int)_position.Y,
           _width,
           _height);
        Rectangle drawRectangle = new Rectangle();

        drawRectangle.X = (int)sprite.Position.X;
        drawRectangle.Y = (int)sprite.Position.Y;
        drawRectangle.Width = sprite.Width;
        drawRectangle.Height = sprite.Height;

        if (panelRectangle.Contains(drawRectangle))
        {
            sprite.Draw(
                spriteBatch,
                drawRectangle,
                null);
        }
        else if (Intersection(panelRectangle, drawRectangle) == null)
        {
            return;
        }
        else if (Intersection(panelRectangle, drawRectangle).HasValue)
        {
            Rectangle intersection = Intersection(panelRectangle, drawRectangle).Value;

            if (Intersection(panelRectangle, drawRectangle) == drawRectangle)
            {
                sprite.Draw(spriteBatch, intersection, intersection);
            }
            else
            {
                sprite.Draw(
                    spriteBatch,
                    intersection,
                    new Rectangle(
                        intersection.X - drawRectangle.X,
                        intersection.Y - drawRectangle.Y,
                        intersection.Width,
                        intersection.Height));
            }
        }
    }

所以我想我的问题是,有没有更好的方法来做到这一点?

更新:刚刚发现了 ScissorRectangle 属性。这似乎是一种不错的方法;它需要制作一个 RasterizerState 对象并将其传递给接受它的 spritebatch.Begin 重载。似乎这可能是最好的选择。还有我显然可以改变的视口。想法? :)

【问题讨论】:

  • 我建议您在问题中使用更明确的表述,类似于“如何在旋转的矩形上执行剪辑?”。
  • 哦,哇,我什至没有考虑轮换。谢谢

标签: xna


【解决方案1】:

有几种方法可以将绘图限制在屏幕的一部分。如果该区域是矩形的(这里似乎就是这种情况),您可以将视口(参见 GraphicsDevice)设置为面板的表面。

对于非矩形区域,您可以使用模板缓冲区或使用深度缓冲区的一些技巧。在模板缓冲区或深度缓冲区中绘制表面形状,将渲染状态设置为仅绘制位于模板/深度缓冲区中刚刚渲染的形状中的像素,最后渲染您的精灵。

【讨论】:

    【解决方案2】:

    一种方法是简单的逐像素碰撞。尽管如果 sprite 很大或很多,这不是一个好主意,但这可能是一种非常简单快捷的方法来完成小 sprite 的工作。首先,对面板进行边界圆或边界正方形碰撞检查,看看您是否甚至需要进行逐像素检测。

    然后,创建一个 contains 方法来检查 sprite 的位置、缩放和旋转是否将它放在面板内,以至于它必须完全被面板包围,因此您不需要每像素碰撞那个案子。这可以很容易地完成,只需创建一个具有精灵对角线长度的宽度和高度的边界方块,并检查与它的碰撞。

    最后,如果这两个都失败了,我们必须进行逐像素碰撞。仔细检查精灵中的每个像素,看看它是否在面板的范围内。如果没有设置像素的alpha值为0。

    就是这样。

    【讨论】:

      猜你喜欢
      • 2011-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-14
      相关资源
      最近更新 更多