Crosswalk sdk サンプル - SLTest
今回はcrosswalkのSLTestというサンプルのソースを解説する。
SLTestはdotXSIを前回サンプルのクラスとは違うクラスで読み込み、
ファイルの全データをambientなどの意味が分かる変数をもつインスタンスとして保持する。
今回はその中から3Dモデルのモデリングデータに関するデータを処理している部分のみ抜粋して見ていく
main関数
main関数は4229行目にある(crosswalk4.1のサンプル)。
最初にゲーム開発環境用の使い方があるが、こちらのほうがわかりやすいのでそこを見ていく。
CSLScene Scene; { //CSLScene Scene; Scene.Open( argv[1] ); Scene.Read(); ShowGlobalSceneInfo(Scene); ShowMaterialLibrary(Scene); // Output the ambience of the scene. CSIBCColorf l_Ambience = Scene.Ambience()->GetColor(); _SI_PRINTF("Ambience has RGB color: %f ; %f ; %f\n", l_Ambience.m_fR, l_Ambience.m_fG, l_Ambience.m_fB) // List all materials for(int i = 0;i < Scene.GetMaterialLibrary()->GetMaterialCount();i ++) { _SI_PRINTF("Material #%d is named %s\n", i, Scene.GetMaterialLibrary()->GetMaterialList()[i]->Name().GetText() ); } DescribeModelRecursively(Scene.Root() ); ShowImageLibrary(&Scene); Scene.Close(); }
前回はXSIParserというクラスを使ったが、今回はCSLSceneというクラスを使う。
このサンプルで使用するクラスは全てCSL***というクラス名になっている。
XSIParserとの違いは、それぞれのテンプレート用のクラスを使ったインスタンスを子に持ち、
それぞれの値に変数でアクセスできる点である。
たとえば光源データがあったとしたら、
XSIParserではXMLのように共通テンプレートのタグ名で"ambient"を探して、そこの数値を使用することになるが、
CSL系のクラスではambientという変数で値を使用することができる。
CSLSceneオブジェクトを作ったら、メンバ関数のOpen()でファイルを開きRead()で中身を読み込む。
XSIParserでは読み込んだ時点でファイルを閉じる関数を呼んでいたが、CSLSceneではすべて終わってからCloseする。
これでCSLSceneオブジェクトが全てのデータをインスタンスとして保持した状態になる。
CSL系クラスの構造
CSLSceneはdotXSIファイルの全データをインスタンスとして持つ。
この中には、シーンに関するシーン概要情報、ファイルバージョンなどの情報、
マテリアル、テクスチャ、フォグ、3Dモデルのポリゴンデータなどが含まれている。
今例に挙げたデータはそれぞれ
CSLMaterialLibrary,
CSLImageLibrary,
CSLFog,
CSLModel(実際はポリゴンデータは違うところに入ってるけど、その辺は後述)
というクラスのデータとして保持している。
この中で今回ほしい3Dモデルのデータを持っているのはCSLModelの中なので、それ以外は省略する。
CSLModel解説
CSLModelはモデリングデータの各部位(ボーン)ごとにわかれているようなデータで、
人間のデータを例にすると足元をルートにして、足、胴体、肩、腕などの部位ごとのデータをツリー構造で持っていることが多い。
このデータの中にそれぞれのマテリアル、モーション、テクスチャ、ローカル変換行列、ポリゴンデータを持っている。
CSLModel以下のクラス構造は以下のようになっている。
- CSLModel
- CSLTransform(変換行列)
- CSLGlobalMaterial(マテリアル)
- CSLCamera(カメラ)
- CSLLightInfo(光源関連)
- CSLXSIMesh(3Dデータ構成データ。今回の目的のデータ)
- CSLXSIShape(頂点座標や法線情報、テクスチャ座標情報を持つ)
- CSLXSITriangleList(三角形ポリゴンに分割した3Dオブジェクト。Shapeの座標リストの何番を使うか、というインデックスデータ)
- CSLXSIPolygonList(上記の多角形ポリゴン版。ポリゴンインデックスの最初に何角形かのデータが付加されている)
- CSLXSITriangleStripList(三角形ポリゴンだがちょっと違う方式。詳しくは"トライアングルストリップ"で検索)
- CSLModel(前述の体の各部位のデータを子に持つ)
CSLXSIMesh
CSLModelの中でモデリングデータだけほしいので、それにあたるCSLXSIMeshクラスを見てみる。
モデリングデータに関してはCSLMeshというクラスもあるが、dotXSIのバージョン5や6以降であればCSLXSIMeshになっているはず。
CSLXSIMeshの構造は前述のクラス構造で一緒に説明しているが、おおまかにその4つのデータを持つ。
CSLXSIShapeはポリゴンを構成する頂点の座標、法線、テクスチャ座標などの実際の数値を小数の配列で保持していて、
それ以外のCSLXSITriangleList,CSLXSIPolygonList,CSLXSITriangleStripListはその頂点データの何番目を使用してポリゴンを書くかという
データを整数で保持している。
頂点データ処理部分
クラス構造の説明からソースの説明に戻り、DescribeXSIMeshという関数を説明する。
処理は大まかにCSLXSIMeshのシェイプとインデックスを読み込む処理に分かれていて、
1番最初にDescribeShapeという関数でシェイプデータを読んでいる。
void DescribeXSIShape(CSLXSIShape* in_pXSIShape) { SI_Int i; CSLXSISubComponentAttributeList* l_pAttributeList; _SI_PRINTF("Shape NbOfVertices %d\n", in_pXSIShape->GetVertexPositionList()->GetCount()); _SI_PRINTF("Shape NbOfNormalArray %d\n", in_pXSIShape->GetNormalListCount() ); l_pAttributeList = in_pXSIShape->GetFirstNormalList(); i = 0; while (l_pAttributeList) { _SI_PRINTF("Shape NormalArray #%d NbOfNormals %d\n", i, l_pAttributeList->GetCount() ); i++; l_pAttributeList = in_pXSIShape->GetNextNormalList(); }
シェイプの処理を順番に見ていくと、
頂点座標の座標数の表示、
法線データリスト数(複数個ある場合もある)の表示、
全法線データリストのそれぞれのデータ数表示
この後、頂点カラーリスト、テクスチャ座標リストに関して法線リストと同じ処理をしている。
これでシェイプ処理部分完了。
次はインデックス処理部分。
下記は多角形ポリゴンインデックスリストの表示部分。
_SI_PRINTF("XSI Mesh NbOfXSIPolyLists %d\n", in_pXSIMesh->GetXSIPolygonListCount() ); int p; for (p=0;p<in_pXSIMesh->GetXSIPolygonListCount();p++) { CSLXSIPolygonList* l_pXSIPolyList = in_pXSIMesh->XSIPolygonLists ()[p]; // Output the material of the XSI polygon list. if(l_pXSIPolyList->GetMaterial() != NULL) { _SI_PRINTF("\tXSIPolyList Material %s\n", l_pXSIPolyList->GetMaterial()->GetName() ); } SI_Int l_nXSIPolyCount = l_pXSIPolyList->GetPolygonCount(); _SI_PRINTF("\tXSIPolyList NbOfXSIPolys %d\n", l_nXSIPolyCount ); SI_Int l_nPolygonNodeCount = l_pXSIPolyList->GetCount(); _SI_PRINTF("\tXSIPolyList NbOfPolygonNode %d\n", l_nPolygonNodeCount ); _SI_PRINTF ( "\tXSIPolygonNodeCountList:" ); for (int np=0;np<l_nXSIPolyCount;np++) { _SI_PRINTF ( "%d,",l_pXSIPolyList->GetPolygonNodeCountArray()->ArrayPtr()[np] ); } _SI_PRINTF ( "\n" ); // output polynode attribute DescribeXSISubComponentList(l_pXSIPolyList); }
ひとつのCSLXSIMeshの中には複数のポリゴンインデックスリストがあるので、まずそのリスト数の表示。
その後、各ポリゴンリストに関して、
マテリアルの表示、
リストに含まれる多角形ポリゴン数の表示、
リストに含まれる多角形ポリゴンの合計頂点数、
多角形ポリゴンの各角数の表示を行う。
最後にDescribeXSISubComponentListが呼ばれているが、
この中で座標インデックスを含む、法線、カラー、テクスチャ座標、その他の頂点に付加するデータ用インデックスリストを表示している。
この後は三角形インデックスリストに関して、同様の処理を行っている。
まとめ
dotXSIファイルにはたくさんのデータが入っていて、そのデータをdirectXやOpenGLで再現するには、
非常に多くのデータを使用する必要があるが、
たとえばテクスチャはプログラム側で決めうち、マテリアルも適当に設定などルールを決めて、
家などの動かないオブジェクトを表示する分には今回説明したCSLXSIMeshのデータを見れば事足りる。
ちょっと3Dデータをプログラムで使いたい場合にはこのCSLSceneを使ってコンバートするといいでしょう。