現在、C# を使用して 3D メディア エンジンに取り組んでいますが、ちょっとした難問に遭遇しました。レンディング ループを把握し、優れたプラグイン アーキテクチャとコンテンツ管理システム、さらにはマテリアル パイプラインをすべて計画しました。エンジンは、両方の API のプログラム可能なパイプラインと共に、DirectX と OpenGL (「レンダラー」プラグイン経由) を使用する予定です。
とにかく、今週の初めに、私は頂点を処理するためのエンジンの抽象レイヤーに取り組み始めました (私はこれを何週間も恐れていました)。また、ご存じの方もいらっしゃると思いますが、グラフィック 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 プラグイン (レンダラー) では、各構造型のセマンティクスを作成できるユーティリティ クラスを作成し、データをキャッシュするだけで、頂点ごとに宣言を再作成する必要がなくなります。
NONE 列挙値を ELementUsage に追加して、カスタム値を何にでも使用できるようにすることもできます...しかし、DirectX では各頂点をマークする必要があるため、OpenGL でのみ機能します...ない。
私の質問:
これを行うためのより良い方法はありますか (属性を使用する以外に)? DirectX で VertexDeclarations を使用しないようにする方法はありますか? 「私の」質問でわからないことはありますか?
編集:
属性を使用する際の問題は、各頂点から要素データを取得することです。メッシュ バッファー内の各頂点の位置を取得したいとします。属性を使用したため、「vertex.Position」だけでは実行できません。「Utility.GetElement(vertex, ElementUsage.POSITION)」のように、頂点構造からフィールド参照を抽出できるユーティリティ メソッドを作成する必要があります。 . このメソッドは、最初にリフレクションを使用して属性を見つけ、次にフィールド値への参照を返す必要があります。値を設定することさえ(私は思う)不可能でしょうか?
もう 1 つの方法は、IElement インターフェイスを作成し、各要素 (Positon、Normal など) を実装することです。インターフェイスには、継承された要素構造内で直接返すことができる Name プロパティを含めることができます。これは、PositionElements の Name プロパティが単に「Positon」を返すようにするためです。
次に、AddElement(IElement)、GetElement(string name)、GetElement(int index)、Insert、Replace などのメソッドを含む Vertex 構造体内に IElement の配列を保持できます。DirectX で認識されるすべての要素を実装して、レンダラー プラグインは、頂点構造を解析して頂点宣言の配列を作成できます。
これに関する問題は、配列 '[]' を頂点要素データとして使用できるかどうかわからないことです。同様に、頂点構造体 (IElement 配列を含む) を DirectX に直接渡し、次に GPU に渡すのを妨げる、配列に含まれる他のバイト (存在する場合) は何ですか?
このように実装することは、私が必要としているものに完全に最適です。もう 1 つの質問は、IElement (要素) の継承型がクラスになる可能性があるか、それとも要素値が値型でなければならないかということです。