2010-02-03 81 views
12

目前在使用C#的3D媒體引擎上工作,我遇到了一些小難題。我已經制定出了我的延期循環,我有了一個出色的插件架構和內容管理系統,甚至還有一個計劃出來的材料管道。然後,引擎計劃使用DirectX和OpenGL(通過「渲染器」插件)以及兩個API的可編程管線。api獨立頂點處理的好代碼結構是什麼?

無論如何,在本週初,我開始研究處理頂點的引擎抽象層(我已經對此持續了數週了)。正如你們中的一些人所知道的,圖形API之間的頂點處理並不是完全相關的或者是相同的。那麼有點相關;),但不一樣。在OpenGL中,處理頂點非常直觀,您可以創建自定義頂點結構,將其發送到GPU,然後讓着色器處理剩餘的頂點結構。這對於靈活的圖形管線是完美的,OpenGL不需要知道每個頂點包含哪些元素。另一方面,DirectX要求我們爲每個頂點結構創建聲明,然後將它們發送給GPU。

問題是,我不知道正在傳遞什麼類型的頂點結構,我一定希望避免創建抽象層,它涉及通過枚舉和一些抽象的「VertexDeclaration」類聲明每個頂點的元素;這會導致一些問題:

1)獲取頂點元素將是一個痛苦的說,至少。我可以使用一些'VertexSemantic'並且詢問頂點'a-z'的位置,但是當處理很多像骨骼動畫這樣的頂點時,它可能會有很多開銷。

2)考慮到引擎的主要焦點是'新手',不是非常用戶友好。我希望用戶能夠創建自定義頂點和網格緩衝區,而無需申報大量對象,因此需要花費寶貴的開發時間。

3)更多?

現在我可以做一些屬性,然後爲DirectX渲染器內的頂點結構創建聲明。例如,繼續前進,創造一些枚舉:

// for getting the format layout of the element 
public enum ElementFormat 
{ 
    Float, Float2, Float3, Byte, etc, etc 
} 
// for determining the 'usage' 
// (here is 'another' where DirectX limits vertex structures ><) 
public enum ElementUsage 
{ 
    Position, Normal, Color, TextureCoord, etc, etc 
} 

現在我可以創建用戶可以應用到自己的頂點結構中的各元素的「場」的屬性:

public class VertexElementAttribute : Attribute 
    { 
     #region Properties 
     /// <summary> 
     /// Gets the total size (in bytes) of the element. 
     /// </summary> 
     public int Size 
     { 
      get; 
      set; 
     } 
     /// <summary> 
     /// Gets the number of values contained with-in the element. 
     /// </summary> 
     public int Count 
     { 
      get; 
      set; 
     } 
     /// <summary> 
     /// Gets the type semantic of the element. 
     /// </summary> 
     public ElementType Type 
     { 
      get; 
      set; 
     } 
     /// <summary> 
     /// Gets the usage semantic of the element. 
     /// </summary> 
     public ElementUsage Usage 
     { 
      get; 
      set; 
     } 
     #endregion 

     #region Init 
     /// <summary> 
     /// Creates a new vertex element attribute. 
     /// </summary> 
     /// <param name="count">The number of values contained within the element.</param> 
     /// <param name="size">The total size (in bytes) of the element.</param> 
     /// <param name="type">The type semantic of the element.</param> 
     /// <param name="usage">The usage semantic of the element.</param> 
     public VertexElementAttribute(int count, int size, ElementType type, ElementUsage usage) 
     { 
      Count = count; 
      Size = size; 
      Type = type; 
      Usage = usage; 
     } 
     #endregion 
    } 

的例子什麼樣的自定義頂點結構可能看起來像:

public struct VertexPositionColor 
{ 
    [VertexElement(3, sizeof(Vector3), ElementType.FLOAT3, ElementUsage.POSITION)] 
    public Vector3 Xyz; 
    [VertexElement(4, sizeof(Color), ElementType.FLOAT4, ElementUsage.COLOR)] 
    public Color Rgba; 

    ... etc 
} 

這將是很好的。在DirectX插件(渲染器)中,我可以創建一個實用程序類,它可以爲每個結構類型創建語義,然後緩存數據,以便不必爲每個頂點重新創建聲明。

我甚至可以爲ELementUsage添加一個無枚舉值,以便自定義值可用於以前的任何方式......但它們再次只能在OpenGL中工作,因爲DirectX需要您標記每個頂點......除非存在是我缺少的東西。

我的問題(S):

有沒有一種更好的方式去關心這個(除了使用attirbutes)? 有沒有辦法避免在DirectX中使用VertexDeclarations? 有沒有什麼事情你可能不瞭解'我的'問題?

編輯:

使用屬性會從每個頂點獲取單元數據的問題。假設我想要獲取網格緩衝區中每個頂點的位置。因爲我使用了屬性,所以我不能只執行'vertex.Position',我不得不創建一個實用程序方法,它可以從頂點結構中提取字段引用,如'Utility.GetElement(vertex,ElementUsage.POSITION)' 。此方法需要使用反射來首先查找屬性,然後將引用返回給字段值。設定價值甚至不會(我認爲)成爲可能?

另一種方法是創建一個IElement接口並實現每個元素(Positon,Normal等)。該接口可以具有Name屬性,我可以直接在繼承的元素結構中返回,就像PositionElements的Name屬性將返回「Positon」一樣。我可以容納IElement的數組,它包含像AddElement(IElement),GetElement(字符串名),GetElement(int index),Insert,Replace等方法的Vertex結構。我將實現所有已知的元素DirectX,以便渲染器插件可以解析頂點結構以創建頂點聲明數組。

問題是我不確定是否可以使用數組'[]'作爲頂點元素數據。比如,數組中包含什麼其他字節(如果有的話)阻止我將Vertex結構(包含IElement數組)直接傳遞給DirectX,然後傳遞給GPU?

以這種方式實現它對於我所需要的是絕對完美的。另一個問題是IElement的繼承類型(元素)可能是一個類,還是元素值必須是值類型?

+2

我推薦看看XNA是如何做到的。 – Foole 2010-02-03 05:14:30

+0

我有,它使用類似於directX的東西......沒有什麼區別。一旦我找到了我們的DirectX渲染器,Xna就會變得簡單。我會再看看我錯過的任何東西,謝謝:)。 – 2010-02-03 05:38:13

+0

看着XNA,它類似於DirectX :(因此沒有幫助。 – 2010-02-03 05:46:23

回答

1

它已經很長一段時間,因爲我已經做任何的DirectX或OpenGL,所以把我的意見與一粒鹽,但我記得做東西這樣前一陣子。

我覺得我做了這樣的事情:

var graphicsStream = new GraphicsStream(); 

var elements = graphicsStream.Create<Vector3>(Usage.Position); 
graphicsStream.Create<Color>(Usage.Color); 
graphicsStream.Create<Quaternion>(Usage.Fribble); 

elements.SetData(new[] { new Vector3(), new Vector3() }); 

var vertexFormat = graphicsStream.GetFormat(); 
graphicsStream.Validate(); // ensure all the streams have the same length 

// get a particular element by type 
var p = graphicsStream.GetData(Usage.Position, 1); 

你必須這是應用了使用一組類型的數據集的圖形流。從這裏你可以生成一個合適的頂點格式。 API可以讓您更改單個元素,或者一次性上傳和替換整個頂點緩衝區。

最大的缺點是您沒有一個結構代表頂點結構中的「列」。我不知道這是不是你要找的東西。爲什麼這樣的設計不合適?

+0

我知道這已經太長了,但你的答案是正確的,你的模式可以很容易地調整,以適應我自己....不是它需要xD。不管怎樣,謝謝。 – 2012-09-29 09:00:09

+0

不客氣=) – jonnii 2012-09-30 22:43:30

相關問題