XNA-矩阵等价于SpriteBatch.绘制变换
本文关键字:绘制 变换 SpriteBatch 等价于 XNA- | 更新日期: 2023-09-27 18:26:08
假设我有这个接口:
interface Drawable {
Vector2 DrawPosition { get; }
Texture2D Texture { get; }
float Rotation { get; }
Vector2 Origin { get; }
Vector2 Scale { get; }
bool FlipHorizontally { get; }
}
在一个扩展Microsoft.Xna.Framework.Game的类中,我覆盖了Draw(GameTime),这段代码就在其中:
Drawable d = ...;
spriteBatch.Begin();
spriteBatch.Draw(d.Texture, d.DrawPosition, new Rectangle(0, 0, d.Texture.Width, d.Texture.Height), Color.White, d.Rotation, d.Origin, d.Scale, d.FlipHorizontally ? SpriteEffects.FlipHorizontally : SpriteEffects.None, 0);
spriteBatch.End();
这将使用SpriteBatch.Draw(Texture2D纹理、Vector2位置、Nullable sourceRectangle、Color颜色、浮动旋转、Vector 2原点、Vector1比例、SpriteEffects效果、浮动层深度)重载。
假设我有一组顶点,它为d返回的图像绘制了一个粗略的轮廓。纹理(也就是说,如果我在Microsoft Paint中打开图像,并用铅笔画出顶点集中的每个点,它将非常适合)。如果我想用GraphicsDevice.DrawUserPrimitives()绘制这些点,以便它们覆盖纹理,有没有一种方法可以只使用矩阵来变换顶点?关键是它只能使用矩阵,而我没有其他的绘画选择,因为我实际上也需要使用转换后的顶点来做其他事情。我已经试过类似的东西了
Matrix.CreateTranslation(new Vector3(-d.Origin, 0))
* Matrix.CreateScale(new Vector3(d.Scale, 0))
* Matrix.CreateRotationZ(d.Rotation)
* Matrix.CreateTranslation(new Vector3(d.DrawPosition, 0)));
但它失败得很厉害。这个问题有解决办法吗?
您的矩阵代码看起来正好适合World矩阵(将模型放置在世界空间中)。所以我猜这是其中之一:
-
基本体在模型空间中的位置不对。精灵批次创建单个多边形,其中(0,0)为精灵的左上角,({纹理宽度},{纹理高度})为右下角。基本体的大小和位置必须相同。
-
投影矩阵错误。看看这个答案。请注意,
SpriteBatch
使用翻转(客户端空间)坐标系。 -
背面剔除模式错误(未考虑翻转坐标系)。
-
你遇到了深度缓冲问题(你需要在远近平面内绘制,你是否被任何东西剔除了深度?)
如果您仍然有问题,请从DirectX SDK获取PIX,并使用它来确定您的游戏实际绘制的内容。
天哪,伙计们,我很抱歉。我刚刚意识到它不匹配的全部原因是因为我把顶点弄错了!好吧,我想如果你们需要帮助做同样的事情,这是我的最终版本:
abstract class Drawable
{
public abstract Vector2 DrawPosition { get; }
public abstract Texture2D Texture { get; }
public abstract float Rotation { get; }
public abstract Vector2 Origin { get; }
public abstract Vector2 Scale { get; }
public abstract bool FlipHorizontally { get; }
public abstract Vector2[] Vertices { get; }
public Matrix TransformationMatrix
{
get
{
return Matrix.CreateTranslation(-new Vector3(Texture.Width * Scale.X / 2, 0, 0))
* Matrix.CreateScale(new Vector3(FlipHorizontally ? -1 : 1, 1, 1))
* Matrix.CreateTranslation(new Vector3(Texture.Width * Scale.X / 2, 0, 0))
* Matrix.CreateTranslation(-new Vector3(Origin, 0))
* Matrix.CreateScale(new Vector3(Scale, 0))
* Matrix.CreateRotationZ(Rotation)
* Matrix.CreateTranslation(new Vector3(DrawPosition, 0));
}
}
}
class Camera
{
private readonly Viewport viewport;
public Matrix GetViewMatrix()
{
return Matrix.CreateScale(1, -1, 1) * Matrix.CreateTranslation(0, viewport.Height, 0);
}
public Vector2 MouseToWorld(int x, int y)
{
return Vector2.Transform(new Vector2(x, y), Matrix.CreateScale(1, -1, 1) * Matrix.CreateTranslation(0, viewport.Height, 0));
}
}
class Game1 : Microsoft.Xna.Framework.Game
{
private Drawable avatar;
private Camera camera;
...
protected override void Initialize() {
avatar = ...;
camera = new Camera(graphics.GraphicsDevice.Viewport);
basicEffect = new BasicEffect(graphics.GraphicsDevice);
basicEffect.VertexColorEnabled = true;
basicEffect.Projection = Matrix.CreateOrthographicOffCenter(0, graphics.GraphicsDevice.Viewport.Width, graphics.GraphicsDevice.Viewport.Height, 0, 0, 1);
base.Initialize();
}
...
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, camera.GetViewMatrix());
spriteBatch.Draw(avatar.Texture, avatar.DrawPosition, new Rectangle(0, 0, avatar.Texture.Width, avatar.Texture.Height), Color.White, avatar.Rotation, avatar.Origin, avatar.Scale, avatar.FlipHorizontally ? SpriteEffects.FlipHorizontally : SpriteEffects.None, 0);
spriteBatch.End();
basicEffect.CurrentTechnique.Passes[0].Apply();
VertexPositionColor[] vertices = new VertexPositionColor[avatar.Vertices.Length + 1];
Matrix m = MakeAffineTransform(avatar);
for (int i = 0; i < avatar.Vertices.Length; i++)
{
vertices[i] = new VertexPositionColor(Vector3.Transform(new Vector3(Vector2.Transform(avatar.Vertices[i], m), 0), camera.GetViewMatrix()), Color.Black);
Console.WriteLine(vertices[i]);
}
vertices[vertices.Length - 1] = vertices[0];
graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineStrip, vertices, 0, vertices.Length - 1);
base.Draw(gameTime);
}
...
}
它工作得很漂亮!这实际上翻转了原点,使其位于左下角,还翻转了y轴,使递增值向上,递减值向下。相机可能是一个很好的基础,可以很容易地更新(比如说,如果你想让它跟随屏幕上的东西),这样你就可以将世界坐标传递给它(原点在左下角),它就会返回屏幕坐标。