XNA matrix equivalent to SpriteBatch.Draw transforms?

Say I have this interface:

interface Drawable { Vector2 DrawPosition { get; } Texture2D Texture { get; } float Rotation { get; } Vector2 Origin { get; } Vector2 Scale { get; } bool FlipHorizontally { get; } } 

and in a class that extends Microsoft.Xna.Framework.Game, I override Draw (GameTime), and this code is somewhere in there:

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

It uses SpriteBatch.Draw (Texture Texture2D, Position Vector2, Nullable sourceRectangle, color, rotation of the float, start Vector2, scale Vector2, effects SpriteEffects, float layerDepth).

Let's say I had a vertex set that makes the rough image scheme returned by d.Texture (that is, if I open the image in Microsoft Paint and pencil each point from the many vertices, this will come up pretty close). If I wanted to build these points so that they looked through textures using GraphicsDevice.DrawUserPrimitives (), would there be a way to convert vertices using only matrices? The main thing is that it can only use matrices, and I have no other alternatives for drawing, because I really need to use the converted vertices for other things. I already tried something like

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

but it is so hard. Is there a solution to this problem?

+4
source share
2 answers

Oh god guys I'm sorry. I just realized that the reason is that this is not a coincidence, because I did the wrong vertices! Well, I think if you guys need help doing the same, here is my final version:

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

It works beautifully! This actually flips the origin so that it is in the lower left corner and also flips the y axis so that increasing values ​​go up and decreasing values ​​go down. The camera can be a good base and can be easily updated (say, if you want to make it follow something on the screen) so that you can give it the coordinates of the world (with a start in the lower left corner) Return the coordinates of the screen.

0
source

Your matrix code looks right for the World matrix (puts the model in world space). Therefore, I assume that this is one of the following things:

  • Your primitives are in the wrong place in model space. Sprite creates one polygon with (0,0), which is the top left edge of the sprite, and ({texture width}, {texture height}) is the bottom right. Your primitives should be the same size and in the same place.

  • Your projection matrix is ​​incorrect. See this answer . Note that SpriteBatch uses an inverted (client-space) coordinate system.

  • Incorrect rejection mode (not counting the inverted coordinate system).

  • You are faced with a depth buffer problem (do you need to draw in the far and near plan and you are a depth knocked out by something?)

If you still have problems, get a PIX from the DirectX SDK and use this to determine what your game is actually drawing.

+2
source

Source: https://habr.com/ru/post/1399116/


All Articles