簡體   English   中英

XNA-等效於SpriteBatch.Draw轉換的矩陣?

[英]XNA - matrix equivalent to SpriteBatch.Draw transformations?

說我有這個界面:

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,顏色,浮點旋轉,Vector2原點,Vector2比例,SpriteEffects效果,浮點layerDepth)重載。

假設我有一組頂點,該頂點對d.Texture返回的圖像進行了粗略的輪廓繪制(也就是說,如果我在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矩陣(將模型放置在世界空間中)。 所以我猜這是其中之一:

  • 您的基元在模型空間中的位置錯誤。 Sprite批處理創建單個多邊形,其中(0,0)是Sprite的左上角,而({texture width},{texture height})是右下角。 您的基本體必須具有相同的大小和位置。

  • 您的投影矩陣是錯誤的。 看到這個答案 請注意, 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軸,以使增加的值向上移動而減少的值向下移動。 相機可能是很好的基礎,並且可以輕松更新(例如,如果要使其跟隨屏幕上的某物),以便可以向其傳遞世界坐標(原點位於左下角),並且ll返回屏幕坐標。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM