2009/2/4 Na-7
 

技術資料一覧に戻る

 

3Dモデルの頂点データの取得

 

注意 この資料は、筆者が自らの経験を記録したものであり、他人に勧めるものではありません。

この資料を参考として行った行為がいかなる結果になろうとも、筆者は責任を負いませんので予めご承知おきください。

 

 

◎使用ツール

ツール名 入手元
XNA3.0(XNA GameStudio 3.0:ゲーム開発用フレームワーク) http://msdn.microsoft.com/ja-jp/xna/default.aspx

 

◎目的

3Dモデルの形状変更、衝突判定、デバッグなどのために、3Dモデルの頂点データを取得する。

(XNA初期バージョンでは取得不可だった模様。XNA2.0以降は取得可能。)

 

 

◎全体の流れ

全ての頂点データを正確に取得しようとするとコードが複雑になるので、手っ取り早く取得する簡易取得サンプルコードを先に示す。

サンプルを流用し実行したら出力結果を確認すること。満足な結果が得られた場合は、以降の手順は不要となる。

 

「欲しいデータ項目が足りない」「値がおかしい(入れ違っている)」といった場合は、さらに以下の手順が必要となる。

追加手順1:3Dモデルの頂点データフォーマットの確認

追加手順2:頂点データフォーマットの定義(カスタム頂点構造体の作成)

追加手順3:頂点データ取得コードの修正

 

 

◎簡易取得サンプルコード

protected override void LoadContent()
{

    〜

    Model model = Content.Load<Model>("Sample1");

    // 頂点データのコピーを取得する
    int elementCount = 5;
    VertexPositionNormalTexture[] v = new VertexPositionNormalTexture[elementCount];
    BufferUsage bu = model.Meshes[0].VertexBuffer.BufferUsage;
    model.Meshes[0].VertexBuffer.GetData<VertexPositionNormalTexture>(v, 0, elementCount);

    // 頂点データをコンソールに出力する
    for (int i = 0; i < elementCount; i++)
    {
        // 一括出力(?)
        Console.WriteLine(v[i].ToString());
        // 個別出力の例
        Console.WriteLine(v[i].Position.X.ToString());
    }

    〜

}

 

 

◎簡易取得サンプルコードの補足

・3Dモデルの頂点数を知りたい場合は、こちらを参考に別途調査すること。

・3Dモデルによっては、頂点データフォーマットが異なる場合がある(参考)。その場合は、 項目が不足したり、データが入れ違いに格納される恐れがあるので、出力結果を自分の目で確認すること。

 →頂点データフォーマットが異なる場合は、後述の追加手順を実施する必要がある

・GetDataの第二引数は「startIndex:コピーを開始する配列要素のインデックス」と記述されているが、XNA3.0で試したら、コピー取得元のインデックスではなくて、コピー貼付先インデックス(新しい配列に格納する位置)のように見えた。(勘違いかもしれないので、各自で確認すること)

 →GetDataによる頂点データのコピーは高速なので、とりあえずバッファ全体をコピーしておき、使用する際にインデックス操作で必要な個所のみ取得することは可能

 

 

◎簡易取得サンプルコードの実行結果

{Position:{X:-407.647 Y:1128.286 Z:57.445} Normal:{X:-0.09745401 Y:-0.8352341 Z:0.5411901} TextureCoordinate:{X:0 Y:0}}
-407.647
{Position:{X:5.324934E-44 Y:1 Z:0} Normal:{X:0 Y:0 Z:-460.744} TextureCoordinate:{X:1145.346 Y:-0.11}}
5.324934E-44
{Position:{X:-0.313024 Y:-0.948799 Z:0.042385} Normal:{X:0 Y:0 Z:1.404381E-41} TextureCoordinate:{X:0.989788 Y:0.010212}}
-0.313024
{Position:{X:0 Y:0 Z:-461.438} Normal:{X:1230.078 Y:72.34499 Z:-0.5384899} TextureCoordinate:{X:0.05707199 Y:0.8406969}}
0
{Position:{X:0 Y:0 Z:5.324934E-44} Normal:{X:1 Y:0 Z:0} TextureCoordinate:{X:0 Y:-407.647}}
0

 

 

出力結果に満足した場合は、以上で終了。

「欲しいデータ項目が不足している」「値がおかしい」といった場合は、以下の追加手順が必要。

 

 

◎追加手順1:3Dモデルの頂点データフォーマットの確認

(ターゲット3Dモデルの頂点データフォーマットを既に知っている場合は、この手順は不要。追加手順2に進むこと。)

以下のコードを参考に、頂点データフォーマットを調査確認すること。

protected override void LoadContent()
{

    〜

    Model model = Content.Load<Model>("Sample1");

    // 頂点データフォーマットを調査する
   
foreach (ModelMesh mesh in model.Meshes)
    {
       
foreach (ModelMeshPart part in mesh.MeshParts)
        {
           
foreach (VertexElement vertexElement in part.VertexDeclaration.GetVertexElements())
            {
               
Console.WriteLine("vertexElement = " + vertexElement);
            }
            Console.WriteLine("---------------------");
        }
    }

    〜

}

 

◎上記コードの実行結果

vertexElement = {Stream:0 Offset:0 Format:Vector3 Method:Default Usage:Position UsageIndex:0}
vertexElement = {Stream:0 Offset:12 Format:Vector3 Method:Default Usage:Normal UsageIndex:0}
vertexElement = {Stream:0 Offset:24 Format:Vector2 Method:Default Usage:TextureCoordinate UsageIndex:0}
vertexElement = {Stream:0 Offset:32 Format:Byte4 Method:Default Usage:BlendIndices UsageIndex:0}
vertexElement = {Stream:0 Offset:36 Format:Vector4 Method:Default Usage:BlendWeight UsageIndex:0}
---------------------
vertexElement = {Stream:0 Offset:0 Format:Vector3 Method:Default Usage:Position UsageIndex:0}
vertexElement = {Stream:0 Offset:12 Format:Vector3 Method:Default Usage:Normal UsageIndex:0}
vertexElement = {Stream:0 Offset:24 Format:Vector2 Method:Default Usage:TextureCoordinate UsageIndex:0}
vertexElement = {Stream:0 Offset:32 Format:Byte4 Method:Default Usage:BlendIndices UsageIndex:0}
vertexElement = {Stream:0 Offset:36 Format:Vector4 Method:Default Usage:BlendWeight UsageIndex:0}
---------------------
・・・

・・・

---------------------

※同じフォーマットが繰り返し表示されることが多い

 

 

◎追加手順2:頂点データフォーマットの定義(カスタム頂点構造体の作成)

以下のコードやこちらの記事を参考に、追加手順1:で確認した内容と同一のカスタム頂点構造体を作成する。

 

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

// Byte4を使用するために追加している。通常は不要。
using Microsoft.Xna.Framework.Graphics.PackedVector;

namespace VertexBufferTest1
{
   
public class Game1 : Microsoft.Xna.Framework.Game
    {

        〜

        public struct VertexPositionNormalTextureBlendIndicesBlendWeight
       
{
           
public Vector3 Position;
           
public Vector3 Normal;
           
public Vector2 TextureCoordinate;
           
public Byte4 BlendIndices;
           
public Vector4 BlendWeight;

            public VertexPositionNormalTextureBlendIndicesBlendWeight(Vector3 position, Vector3 normal, Vector2 textureCoordinate, Byte4 blendIndices, Vector4 blendWeight)
            {
               
this.Position = position;
               
this.Normal = normal;
               
this.TextureCoordinate = textureCoordinate;
               
this.BlendIndices = blendIndices;
               
this.BlendWeight = blendWeight;
            }

            public static readonly VertexElement[] VertexElements
                = {
               
new VertexElement(
                    0,
                    0,
                   
VertexElementFormat.Vector3,
                   
VertexElementMethod.Default,
                   
VertexElementUsage.Position,
                    0
                ),

                new VertexElement(
                    0,
                   
sizeof(float) * 3,
                   
VertexElementFormat.Vector3,
                   
VertexElementMethod.Default,
               
    VertexElementUsage.Normal,
                    0
                ),

                new VertexElement(
                    0,
                   
sizeof(float)*(3 + 3),
                   
VertexElementFormat.Vector2,
                   
VertexElementMethod.Default,
                   
VertexElementUsage.TextureCoordinate,
                    0
                ),

                new VertexElement(
                    0,
                   
sizeof(float)*(3 + 3 + 2),
                   
VertexElementFormat.Byte4,
                   
VertexElementMethod.Default,
                   
VertexElementUsage.BlendIndices,
                    0
                ),

                new VertexElement(
                    0,
                   
sizeof(float)*(3 + 3 + 2) + 4,
                   
VertexElementFormat.Vector4,
                   
VertexElementMethod.Default,
                   
VertexElementUsage.BlendWeight,
                    0
                )
            };
        }

        〜

    }
}

 

 

◎追加手順3:頂点データ取得コードの修正

頂点データ取得コードを、追加手順2で作成したカスタム頂点構造体に置き換える。

簡易取得サンプルコードの場合は、VertexPositionNormalTextureと記述された3箇所をVertexPositionNormalTextureBlendIndicesBlendWeightに置き換える。

 

 

◎追加手順1〜3を実施した場合の実行結果

VertexBufferTest1.Game1+VertexPositionNormalTextureBlendIndicesBlendWeight
-407.647
VertexBufferTest1.Game1+VertexPositionNormalTextureBlendIndicesBlendWeight
-460.744
VertexBufferTest1.Game1+VertexPositionNormalTextureBlendIndicesBlendWeight
-461.438
VertexBufferTest1.Game1+VertexPositionNormalTextureBlendIndicesBlendWeight
-407.647
VertexBufferTest1.Game1+VertexPositionNormalTextureBlendIndicesBlendWeight
-460.361

 

inserted by FC2 system