XNA ViewPort projection and SpriteBatch

本小妞迷上赌 提交于 2019-12-18 11:43:17

问题


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();

回答1:


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).



来源:https://stackoverflow.com/questions/3570192/xna-viewport-projection-and-spritebatch

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!