Top > ComputerGraphics > XNA > Vertex > HowToMakeCustomVertex
Last-modified: Sat, 09 Jun 2012 18:11:35 JST
Counter:2961 Today:1 Yesterday:0 Online:7
このエントリーをはてなブックマークに追加

カスタム頂点(宣言)構造体について

About

 頂点を操作する構造を作ろうとすると、XNAフレームワーク側で用意された元のは別に、独自に定めた頂点データが必要になることがある。ここではその作り方について言及する。

  • 2012/5/4現在特にサンプルを用意していません。

サンプルにするカスタム頂点

 ここではAppHub「パーティクル 3D」で取り扱われているカスタム頂点宣言構造体「ParticleVertex」を例にしている。そのソースコードは以下の通り。以降はこのソースコードの成り立ちについて解説する。

    struct ParticleVertex:IVertexType
    {

        // この頂点がパーティクルのどのコーナーに相当するかを保存します。
        public Short2 Corner;

        // パーティクルの開始位置を格納します。
        public Vector3 Position;

        // パーティクルの開始速度を格納します。
        public Vector3 Velocity;

        // 各パーティクルをわずかに異なる外観にするための 4 つのランダム値。
        public Color Random;

        // このパーティクルの作成時刻 (秒単位)。
        public Single Time;

        // この頂点構造体のレイアウトを記述します。
        public static readonly VertexDeclaration VertexDeclaration =
            new VertexDeclaration(

                new VertexElement(0, VertexElementFormat.Short2,
                                     VertexElementUsage.Position, 0),
                new VertexElement(4, VertexElementFormat.Vector3,
                                     VertexElementUsage.Position, 1),
                new VertexElement(16, VertexElementFormat.Vector3,
                                      VertexElementUsage.Normal, 0),
                new VertexElement(28, VertexElementFormat.Color,
                                      VertexElementUsage.Color, 0),
                new VertexElement(32, VertexElementFormat.Single,
                                      VertexElementUsage.TextureCoordinate, 0)
            );

        // この頂点構造体のサイズ
        public const int SizeInBytes = 36;//上記Offsetの最初の4byte+最後の位置で求められる。

        /// <summary>
        /// VertexDeclarationを返す.IVertexTypeの実装
        /// </summary>
        VertexDeclaration IVertexType.VertexDeclaration
        {
            get { return VertexDeclaration; }
        }

    }

頂点情報に含めるデータを定義する

 頂点情報の構造を作るので、まずは頂点情報に何のデータが必要であるかをフィールドに定義する。ここではAppHubのパーティクルの例に倣って、次の様にフィールドを定義した。

        // この頂点がパーティクルのどのコーナーに相当するかを保存します。
        public Short2 Corner;

        // パーティクルの開始位置を格納します。
        public Vector3 Position;

        // パーティクルの開始速度を格納します。
        public Vector3 Velocity;

        // 各パーティクルをわずかに異なる外観にするための 4 つのランダム値。
        public Color Random;

        // このパーティクルの作成時刻 (秒単位)。
        public Single Time;

 ここで注意しなければならないのは、原則として「VertexElementFormat Enumeration(列挙体)」に含まれる型(値)でこれらを定義しなければならないという点である。「Short2」などは特に顕著で、普通にプログラムを書いていく分には利用しない。「VertexElementFormat列挙体」のメンバーについてはMSDNを参照されたい。

実際問題「Single」は「float」と同義で、フィールドに定義する段階では「float」としても問題ない様子(AppHubのパーティクルサンプルはfloatで宣言されている)。ただどうせ以降の項目「Decralation」の定義時に「VertexElementFormat」の型で定義しなおすので、表記の都合上、分かりやすいように予め「VertexElementFormat」のメンバーで型定義しておいた方が無難である。次項も合わせて確認されたい。

頂点宣言VertexDeclarationを定義する

 頂点宣言「VertexDeclaration」周りが非常にややこしい。「VertexDeclaration」は端的に言えば、その頂点データがどのような構造になっているかを示す値である。プログラムはこのデータを元にして適切に頂点データを管理している。

IVertexTypeを使う

 XNA4.0以前では明示的に示す必要があった「VertexDeclaration(頂点宣言=頂点情報であることを保証する)」だが、XNA4.0からは改善されて「IVertexType」インターフェースが提供されている。「IVertexType」インターフェースは、「VertexDeclaration」プロパティを提供するインターフェースで、自分で作成したCustom頂点構造体に実装すれば、構造体と頂点宣言(VertexDeclaration)が対応していることを約束できる。

VertexDeclarationはVertexElementの配列である

 「頂点宣言VertexDeclaration」は「頂点要素VertexElement」の配列で構成されている。頂点要素とは、そのデータがどのような値であるかを示す値である。要するに先ほど定義した、構造体のフィールドがどういう値であるか、を示すために必要になる。次のソースコードは取りあえず今回扱うVertexDeclarationの定義とそのVertexElementを示したものである。

public static readonly VertexDeclaration VertexDeclaration =
            new VertexDeclaration(

                new VertexElement(0, VertexElementFormat.Short2,
                                     VertexElementUsage.Position, 0),
                new VertexElement(4, VertexElementFormat.Vector3,
                                     VertexElementUsage.Position, 1),
                new VertexElement(16, VertexElementFormat.Vector3,
                                      VertexElementUsage.Normal, 0),
                new VertexElement(28, VertexElementFormat.Color,
                                      VertexElementUsage.Color, 0),
                new VertexElement(32, VertexElementFormat.Single,
                                      VertexElementUsage.TextureCoordinate, 0)
            );

 VertexDecralationがVertexElementの配列で構成されていることが見て分かる。上から順に先に定義したCustom頂点構造体のフィールド「Corner,Position,Velocity,Random,Time」に対応している。次に「VertexElement」のインスタンス生成に必要な引数について解説する。

VertexElementコンストラクタの引数

 空のコンストラクタが存在するが、基本的には4つ引数を取ってインスタンスを生成する。

  • offset:オフセット
  • VertexElementFormat
  • VertexElementUsage
  • UsageIndex

 1番目の引数である「offset:オフセット」が最初にして最大のポイントである。ようするに頂点バッファの先頭から何バイト分、何バイト目のデータが、独自に定義した種類のデータであるかを示すための値となっている。このバイト数は設定値によって変動するので注意する。オフセットのバイト数を決定するのは、引数の2番目に定義する「VertexElementFormat」の値である。対応するバイト数はMSDNの「VertexElementFormat Enumeration」の項目に掲載されている。一応オフセットを計算した結果を掲載している資料が見つからなかったので右の様に表にしておいた(正確性確認のため必ずMSDNを参照されたい)。カスタム頂点構造体に定義したフィールドの型と同じ型を2番目の引数「VertexElementFormat」に設定する。オフセットは1つ前に定義した「VertexElement」に依存して定義される。1つ前の要素の「VertexElementFormat」がVector3だった場合、オフセットは12足される。オフセットは0から始まり定義の度に蓄積して加算されていく。

MemberByte(offset)
Single32bit = 4byte
Vector232bit * 2 = 4byte * 2 = 8byte
Vector332bit * 3 = 4byte * 3 = 12byte
Vector432bit * 4 = 4byte * 4 = 16byte
HalfVector216bit * 2 = 2byte * 2 = 4byte
HalfVector416bit * 4 = 2byte * 4 = 8byte
Color4byte (各色8bit * 4 = 32bit = 4byte)
NormalizedShort216bit * 2 = 2byte * 2 = 4byte
NormalizedShort416bit * 4 = 2byte * 4 = 8byte
Short216bit * 2 = 2byte * 2 = 4byte
Short416bit * 4 = 2byte * 4 = 8byte

 3番目の引数である「VertexElementUsage」は、その頂点データを何の目的で利用するかを示す値である。利用できる値はMSDNの「VertexElementUsage Enumeration 」に一覧されている。

 4番目の引数「UsageIndex」は、3番目の引数「VertexElementUsage」の値が「VertexDecralation」の中で重複した場合に0以外の値を取る。例えばサンプルに上げたソースコードでは、「VertexElementUsage.Position」が重複したので、これを識別するためにそれぞれ0と1の値を与えている。重複しない限り基本的には0を指定しておく。

References