目前在使用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的繼承類型(元素)可能是一個類,還是元素值必須是值類型?
我推薦看看XNA是如何做到的。 – Foole 2010-02-03 05:14:30
我有,它使用類似於directX的東西......沒有什麼區別。一旦我找到了我們的DirectX渲染器,Xna就會變得簡單。我會再看看我錯過的任何東西,謝謝:)。 – 2010-02-03 05:38:13
看着XNA,它類似於DirectX :(因此沒有幫助。 – 2010-02-03 05:46:23