2012-03-01 131 views
4

說我有這樣的接口:XNA - 相當於SpriteBatch.Draw轉換的矩陣?

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

,並在擴展Microsoft.Xna.Framework.Game一類,我重寫抽獎(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顏色,浮動旋轉,Vector2原點,Vector2縮放,SpriteEffects效果,float 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))); 

但它很難失敗。有沒有解決這個問題的方法?

+0

「它失敗很難」並不足以描述發生的事情。 – 2012-03-01 07:45:14

回答

0

哦,我的天啊,我很抱歉。我剛剛意識到它不匹配的全部原因是因爲我把頂點錯了!好吧,我想如果你們在做同樣的事情時需要幫助,這裏是我的最終版本:

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軸,使得增加的值向上並且減小的值向下。相機可能是一個很好的基礎,可以很容易地更新(例如,如果你想讓它跟隨屏幕上的某些東西),以便你可以傳遞世界座標(它的原點位於左下角)將返回屏幕座標。

2

矩陣代碼看起來是正確的世界矩陣(在世界空間放置一個模型)。所以我的猜測是這些東西之一:

  • 您的原語在模型空間中是錯誤的地方。 Sprite批次創建一個單一的多邊形,其中(0,0)是精靈的左上角,({紋理寬度},{紋理高度})是右下角。你的基元需要是相同的大小和相同的地方。

  • 您的投影矩陣是錯誤的。請參閱this answer。請注意,SpriteBatch使用翻轉(客戶端空間)座標系。

  • 你的背面剔除模式是錯誤的(不包括翻轉座標系統)。

  • 你所遇到的深度緩衝的問題(你需要進行內部的遠近平面,並且你正在深入的東西剔除在畫什麼?)

如果您仍然有問題,獲得PIX從DirectX SDK開始,並使用它來確定遊戲實際繪製的內容。