如何在旋转的矩形上执行剪裁?

时间:2011-02-09 21:42:30

标签: xna

所以我有这个Panel类。这有点像一个窗口,你可以调整大小,关闭,添加按钮,滑块等。就像你们中的任何人都记得的那样,就像Morrowind中的状态屏幕一样。我想要的行为是,当一个精灵在面板的边界之外时,它不会被绘制,如果它部分在外部,则只绘制内部的部分。 所以它现在做的是首先得到一个代表面板边界的矩形,一个精灵的矩形,它找到两者之间交叉的矩形,然后将该交点转换为精灵矩形的局部坐标并使用< em>那个源矩形。它的工作原理和我觉得代码一样聪明,我无法感觉到有更好的方法来做到这一点。此外,通过此设置,我无法为我的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重载。看起来这可能是最好的选择。还有Viewport,我显然可以改变它。思考? :)

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

这样做的一种方法是简单的逐像素碰撞。虽然如果精灵很大或很多,这是一个坏主意,但这可以是一个非常简单快捷的方法来完成小精灵的工作。首先,对面板进行边界圆或边界方冲突检查,看看是否需要进行逐像素检测。

然后,创建一个contains方法,检查sprite的位置,比例和旋转是否将它放在面板内,它必须完全被面板包围,这样你就不需要像素间碰撞那种情况。这可以通过创建一个具有精灵对角线长度的宽度和高度的边界正方形并检查与之碰撞来轻松完成。

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

多数民众赞成。