XNA ViewPort 投影和 SpriteBatch

发布于 2024-09-15 20:38:38 字数 1879 浏览 1 评论 0原文

我正在开发 XNA 游戏,并且使用 ViewPort.Project 和 ViewPort.Unproject 在世界坐标之间进行转换。目前,我将这些用于使用 SpriteBatch 绘制的每个对象。我想做的是计算一个矩阵,我可以将其发送到 SpriteBatch.Begin 来为我进行屏幕空间转换。

以下是我当前用于在屏幕空间之间进行转换的函数:

        Vector2 ToWorldCoordinates(Vector2 pixels)
    {
        Vector3 worldPosition = graphics.GraphicsDevice.Viewport.Unproject(new Vector3(pixels, 0),
                Projection, View, Matrix.Identity);
        return new Vector2(worldPosition.X, worldPosition.Y);
    }

    Vector2 ToScreenCoordinates(Vector2 worldCoords)
    {
        var screenPositon = graphics.GraphicsDevice.Viewport.Project(new Vector3(worldCoords, 0),
                Projection, View, Matrix.Identity);
        return new Vector2(screenPositon.X, screenPositon.Y);
    }

View 设置为 Matrix.Identity,Projection 设置如下:

Projection = Matrix.CreateOrthographic(40 * graphics.GraphicsDevice.Viewport.AspectRatio, 40, 0, 1);

这是我当前绘制内容的方式:

            spriteBatch.Begin();
        foreach (var thing in thingsToDraw)
        {
            spriteBatch.Draw(thing.Texture, ToScreenCoordinates(thing.PositionInWorldCoordinates), thing.Color);
            spriteBatch.End();
        }
        spriteBatch.End();

这就是我想要做的(使用 XNA 4.0版本的SpriteBatch.Begin())

            // how do I calculate this matrix?
        Matrix myTransformationMatrix = GetMyTransformationMatrix();

        spriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null, null,
            myTransformationMatrix);

        foreach (var thing in thingsToDraw)
        {
            // note: no longer converting each object's position to screen coordinates
            spriteBatch.Draw(thing.Texture, thing.PositionInWorldCoordinates, thing.Color);
            spriteBatch.End();
        }
        spriteBatch.End();

I'm working on an XNA game and I am using ViewPort.Project and ViewPort.Unproject to translate to and from world coordinates. Currently I use these for each object I draw with SpriteBatch. What I would like to do is calculate a Matrix that I can send to SpriteBatch.Begin to do the screen-space transformation for me.

Here are the functions I currently use to translate to and from screenspace:

        Vector2 ToWorldCoordinates(Vector2 pixels)
    {
        Vector3 worldPosition = graphics.GraphicsDevice.Viewport.Unproject(new Vector3(pixels, 0),
                Projection, View, Matrix.Identity);
        return new Vector2(worldPosition.X, worldPosition.Y);
    }

    Vector2 ToScreenCoordinates(Vector2 worldCoords)
    {
        var screenPositon = graphics.GraphicsDevice.Viewport.Project(new Vector3(worldCoords, 0),
                Projection, View, Matrix.Identity);
        return new Vector2(screenPositon.X, screenPositon.Y);
    }

View is set to Matrix.Identity, and Projection is set like so:

Projection = Matrix.CreateOrthographic(40 * graphics.GraphicsDevice.Viewport.AspectRatio, 40, 0, 1);

And here is how I currently draw things:

            spriteBatch.Begin();
        foreach (var thing in thingsToDraw)
        {
            spriteBatch.Draw(thing.Texture, ToScreenCoordinates(thing.PositionInWorldCoordinates), thing.Color);
            spriteBatch.End();
        }
        spriteBatch.End();

This is what I would like to do instead (using XNA 4.0 version of SpriteBatch.Begin())

            // how do I calculate this matrix?
        Matrix myTransformationMatrix = GetMyTransformationMatrix();

        spriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null, null,
            myTransformationMatrix);

        foreach (var thing in thingsToDraw)
        {
            // note: no longer converting each object's position to screen coordinates
            spriteBatch.Draw(thing.Texture, thing.PositionInWorldCoordinates, thing.Color);
            spriteBatch.End();
        }
        spriteBatch.End();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不再见 2024-09-22 20:38:38

我写过关于 SpriteBatch 和各种“空间”(世界、投影、客户端等)这里这里在这里。这些答案可能值得一读。

SpriteBatch 假设您的世界空间与客户端空间相同 - 无论视口的高和宽有多少像素,原点在左上角,Y+ 向下。

看起来(基于您对CreateOrthographic的使用)您希望您的世界空间在屏幕上显示为 40 个单位高,并且无论多少个单位都适合宽度。您还希望世界原点位于屏幕中心,并且 Y+ 向上。

因此,您必须在两者之间添加另一个矩阵,以将您的世界空间转换为客户端空间。我相信正确的矩阵是(伪代码):scale(40/viewport.Height) * scale(1, -1) * translate(viewport.Width/2, viewport.Height/2)。缩放、翻转和平移以从世界到客户端。

您还必须记住,精灵假定 Y+ 已关闭。因此,您必须将 (1, -1) 比例传递到 SpriteBatch.Draw 中,否则它们将被反转绘制(并且由于背面剔除,它们将不可见)。

I've written about SpriteBatch and the various "spaces" (world, projection, client, etc) here, here and here. Those answers are probably worth reading.

SpriteBatch assumes that your World space is the same thing as Client space - which is however many pixels tall and wide the viewport is, origin top-left, Y+ is down.

It looks like (based on your use of CreateOrthographic) you want your World space to appear as 40 units tall, on screen, and however many units will fit widthways. You also want the World origin at the centre of the screen and Y+ is up.

So you have to stick another matrix in between to convert your World space to Client space. I believe the correct matrix is (in psudocode): scale(40/viewport.Height) * scale(1, -1) * translate(viewport.Width/2, viewport.Height/2). Scale, flip and translate to go from World to Client.

You must also remember that sprites assume that Y+ is down. So you have to pass a (1, -1) scale into SpriteBatch.Draw, otherwise they will be drawn inverted (and, due to backface culling, be invisible).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文