XNA ViewPort 投影和 SpriteBatch
我正在开发 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我写过关于
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 intoSpriteBatch.Draw
, otherwise they will be drawn inverted (and, due to backface culling, be invisible).