Xファイルの読み込み 第1回 〜頂点データを読む〜

はぁ〜パソコンが壊れて中断していたゲーム開発を再開しました。結構プログラムをいじったので、連載記事っぽくこのネタでしばらく更新します。

さてさて、先月の日記でも書きましたが、横で紹介しているゲームはダンジョンを自動生成するため、マップのパーツをXファイルで持っておいて、それからD3DXのMeshに読み込んで適当な位置にいちいち配置していました。ステージ全体を一つのMeshに出来ないので仕方がないですね。

しかしながら、この方式には以下のような問題点が…

  • 膨大な数のMeshを一度に描画しなくてはならない。
  • つ〜か、D3DXメッシュが微妙に遅い


の2点です。(まぁ、実はそのほかにも色々とあるのですが。)

で、気分転換に(何のだよ)それらの問題を消去してみようというわけです。

え〜っと、まずは2の方から…

今まではD3DXのコンストラクタでXファイルを読んでいたのですが、今回は全部自分で1から書いていくことにしたため、Xを読まなくてはいけません。幸い、Xファイルにはご丁寧にテンプレートが書かれているので、それを参考に欲しい情報を読み取ってやります。Xファイル内にはこんなデータが入っていました。(メタセコイアで書き出した場合)

  • 頂点データ
  • インデックスデータ(フェイスデータ)
  • マテリアルリスト
  • 法線ベクトルデータ
  • テクスチャー座標



と、こんな感じの順番で入っているようです。今までと同じように描画するにはこれら全ての情報が必要になるわけです。しかも、インデックスデータは三角形の物と四角形のものがいて、これもまた面倒なことに。この問題は後で対処するつもりで、今回はメタセコイアのデータの時点で全ての四角面を三角に分断してから出力することにしました。 

では、実際のデータを読んでいきます。メッシュ(上のリストの情報の)本体は、

	Mesh {
		頂点の総数;
		頂点座標がずらずらと;
		
		フェイス(三角形)の総数;
		頂点へのインデックスがずらずらと;
		
		MeshMaterialList {
			…省略…
		}
		
		MeshNormals {
			法線座標の総数;
			法線座標がずらずらと;
			法線インデックスの総数(多分三角の数と同じ);
			インデックス情報がずらずらと;
		}
		MeshTextureCoords {
			頂点の総数;
			テクスチャ座標u;テクスチャ座標v; の繰り返しがずらずらと…
		}
	}

といった構造になっています。(多分、書き出すソフトによって変わるんだろうな…)テキストを先頭から読んでいってもいいですし、それ以外の方法を使ってもいいでしょう。僕は面倒なのでこの前覚えた正規表現を使って適当に文字列を切り出して解析していきました。(これをやるとすごく遅いのであまりお勧めはしませんが。)

で、頂点データの読み込みです。はじめの方にずらずらと座標が書かれているのでそれを読んでいきます。使う頂点の形式は、ライティング、テクスチャマッピング共に行うので「CustomVertex.PositionNormalTextured」を使います。こいつは、頂点データX,Y,Zと法線ベクトルのデータNx,Ny,Nz、そしてテクスチャ座標データTu,Tvと合計8個のデータを持ちます。(テクスチャステージを一つしか使わない時ですが。)つ〜ことで、こいつの配列を頂点の総数分生成して、それに頂点座標を書き込んでいきます。

//tVerts は string型の配列 中身は「X座標;Y座標;Z座標」の形式の文字列

	CustomVertex.PositionNormalTextured[] verts = 
		new CustomVertex.PositionNormalTextured[tVerts.Length];
	for (int i = 0; i < tVerts.Length; i++)
	{
		string[] vel = tVerts[i].Split(';');
		verts[i].X = float.Parse(vel[0]);
		verts[i].Y = float.Parse(vel[1]);
		verts[i].Z = float.Parse(vel[2]);
	}

かなりいい加減なサンプルですが…え〜っと、上の構造の例で言うところの「頂点座標がずらずらと;」の部分には「頂点データ1,頂点データ2,頂点データ3,…;」という形式でテキストが書き込まれています。これを、頂点データごとに文字列の配列に分けておきます。つまり「,」で区切ってstring[]にしておけばいいわけです。これはstring.Split(',')とやればすぐに出来るでしょう。そうして作ったのが、文字列配列tVertsです。それをまた「;」で区切ってそれぞれの座標に書き込んでいます。

こんな感じで、頂点座標が取得できます。っても、これだけじゃまったく描画できないんですけどね。今回はメタセコイアで書き出したXファイル(アニメーションなし)という限定的な条件で読み込んでいるので、意外とコードも簡単です。特に.NETには文字列処理系のメソッドが豊富にそろっているので簡単に読み込めるでしょう。

では、次回はフェイスデータ、つまりインデックスバッファを読み込んで最低限描画が出来る状態にしましょう。インデックスバッファで描画しているManagedのサンプルはほとんどないので調べるのが少し面倒でした。それでは〜〜

つ〜か、こんなところで書かずに講座更新しろよ…俺…