テクスチャ座標は、各頂点が画像のどの位置にあたるかを比率で示したものである。
XY平面マップを作成する時は、メッシュ頂点のX,Y座標の最小値と最大値を求め、 各頂点座標を(最大値-最小値)で割ったものが各頂点のテクスチャマップになる。 void CreateTextureMapFlat(int v_num, D3DXVECTOR3 *v, D3DXVECTOR2 *texmap) { int i; D3DXVECTOR3 v_min = v[0]; D3DXVECTOR3 v_max = v[0]; for(i=1;i<v_num;i++){ if(v[i].x < v_min.x) v_min.x = v[i].x; else if(v[i].x > v_max.x) v_max.x = v[i].x; if(v[i].y < v_min.y) v_min.y = v[i].y; else if(v[i].y > v_max.y) v_max.y = v[i].y; } for(i=0;i<v_num;i++){ texmap[i].x = v[i].x / (v_max.x - v_min.x); texmap[i].y = v[i].y / (v_max.y - v_min.y); } } |
Y軸方向のベクトルを中心に、一周するようなテクスチャ座標を作成する時は、
メッシュの中心点から各頂点座標への角度をテクスチャのX座標にする。 テクスチャのY座標は、平面マップと同じである。 void CreateTextureMapRound(int v_num, D3DXVECTOR3 *v, D3DXVECTOR2 *texmap) { int i; D3DXVECTOR3 v_min = v[0]; D3DXVECTOR3 v_max = v[0]; D3DXVECTOR3 v_center; for(i=1;i<v_num;i++){ if(v[i].x < v_min.x) v_min.x = v[i].x; else if(v[i].x > v_max.x) v_max.x = v[i].x; if(v[i].y < v_min.y) v_min.y = v[i].y; else if(v[i].y > v_max.y) v_max.y = v[i].y; if(v[i].z < v_min.z) v_min.z = v[i].z; else if(v[i].z > v_max.z) v_max.z = v[i].z; } v_center.x = (v_max.x - v_min.x) / 2; v_center.z = (v_max.z - v_min.z) / 2; for(i=0;i<v_num;i++){ float roll = (float)atan2(v[i].x - v_center.x, v[i].z - v_center.z) * 180 / PI; if(roll < 0) roll += 360; else if(roll > 360) roll -= 360; texmap[i].x = (float)(360.0f-roll)/360; texmap[i].y = v[i].y / (v_max.y - v_min.y); } } |
ECTIK では、DirectXFileCreate() で、一つずつ必要なテンプレートを保存してXファイルを作成する。
先ず、必要なテンプレートを保存し、次に、そのテンプレートの形式に合わせてデータを保存する。 例えば、アニメーション速度を保存したい場合は、 template AnimTicksPerSecond { <9e415a43-7ba6-4a73-8743-b73d47e88476> DWORD AnimTicksPerSecond; } AnimTicksPerSecond { 120; } となる。 テンプレートの形式は、 template <template-name> { <UUID> 変数 または テンプレート ... } であり、場合により使わない変数(テンプレート)が存在する場合は、[...] を加えると、 テンプレートで定義されていない変数(テンプレート)も使用できるようになる。 // Xファイルオブジェクトの作成 DirectXFileCreate(&pFile); // テンプレートの登録 Register_Templates(pFile); pFile->CreateSaveObject(filename, format, &pSaveObj); // テンプレートの保存 pSaveObj->SaveTemplates(); // データの保存 pSaveObj->CreateDataObject(); ([...] のテンプレートは、pFileData->AddDataObject で追加する) // ファイルに保存 pSaveObj->SaveData(); |
メッシュは、座標変換なしメッシュ、座標変換ありパーツメッシュ、座標変換ありスキンメッシュ の3種類において、それぞれ場合分けして保存しなくてはならない。
座標変換なしメッシュは、フレーム(ユニット)なしで、直接ルートにメッシュ情報を入れる。 座標変換ありパーツメッシュは、先ず階層順にフレーム情報を入れてから、パーツメッシュをそれぞれの親フレームの中に保存する。 座標変換ありスキンメッシュは、ルートにフレームを作成してスキンメッシュを全てその中に入れて、その後にそれとは別に階層順にフレーム情報を保存する。 スキンの階層フレーム情報には、各パーツのスキン情報や頂点の重複情報なども入る。 頂点の重複情報とは、スキンパーツに分割したときに発生する重複のことである。 フレームの中と、スキン情報の中に行列を保存するようになっているが、それらについては次で説明する。 |
座標変換の保存方法には、3種類あり、AnimationKey テンプレートで指定する。
keyType が、0,1,2 の場合は、回転(0) と拡大縮小(1) と平行移動(2) を別々に保存する。 3 の場合は、おそらくそれらを一つの行列に変換したものを保存する。 4 の場合は、原点へ平行移動→ 拡大縮小→回転→元の位置へ平行移動 などの 3 以外の形式の行列を保存する。 0,1,2,3 は、最初の原点への平行移動を省略してある。 そのため、座標変換ありパーツメッシュの場合は、原点へ平行移動した後のメッシュ情報を最初から保存しておかなくてはならない。 本来、スキンメッシュもそうしなくてはならないが、してしまうと具合が悪い。 そのため、スキンメッシュの場合は、スキン情報の中に各フレーム座標から原点への平行移動行列を入れるのである。 もちろん、keyType 4 のスキンメッシュの場合は、単位行列で良い。 回転には、クォーターニオンを入れるが、回転軸のベクトルは(Z軸, Y軸, -X軸)になっている。 X,Y,Z軸についての回転は、一つの回転軸についてのクォーターニオンに変換しなくてはならない(ソースを参照)。 X,Y,Z軸についての回転クォーターニオンを掛け合わせる順番は、X→Y→Zの順だが、X軸は Z軸、 Y軸は Y軸、Z軸は -X軸についての回転である。 keyType が 0 (おそらく 3 も)の場合は、クォーターニオンの最初に、(1,0,0,0) のクォーターニオンを掛け合わせる必要がある(keyType が 4 の場合は必要なし)。 (1,0,0,0) のクォーターニオンは、Z軸についての180度の回転である。 平行移動には、本来の移動に、原点から各フレーム座標への移動と、更にその親フレーム座標から原点への移動を加えなくてはならない。 フレーム座標と親フレーム座標の移動は、座標変換ありパーツメッシュのメッシュ情報を保存するときの行列にも保存する必要がある。 もちろん、keyType 4 の場合は、どちらも必要ない。 |
[cube_skin.x] のスキンの重みは以下のようになっている。
親子関係にあるフレームの子には、親の1.0ではない重みを、1.0からそれを引き算した値を重みとして追加する。 以下の場合は、頂点番号 0 と 1 が該当する。 SkinWeights { "Frame_001"; 6; 0, 1, 4, 5, 6, 7; 0.700000, 0.400000, 1.000000, 1.000000, 1.000000, 1.000000; 1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,0.000000,1.000000;; } SkinWeights { "Frame_002"; 4; 0, 1, 2, 3; 0.300000, 0.600000, 1.000000, 1.000000, 1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,0.000000,1.000000,0.000000,0.000000,0.000000,0.000000,1.000000;; } スキンは、XSkinMeshHeader テンプレートも必要である。 template XSkinMeshHeader { <3CF169CE-FF7C-44ab-93C0-F78F62D172E2> WORD nMaxSkinWeightsPerVertex; WORD nMaxSkinWeightsPerFace; WORD nBones; } XSkinMeshHeader { 1; 1; 2; } 実は分かっていないのだが、 nMaxSkinWeightsPerVertex は、おそらく、1頂点あたりにSkinWeightsが重複している数の最大数、 nMaxSkinWeightsPerFace は、おそらく、1面あたりに一意のSkinWeightsが重複している数の最大数、 nBones は、おそらく、SkinWeights{} の数 と思われる。 |
・基本的に必要なテンプレート
Header Vector Coords2d Matrix4x4 ColorRGBA ColorRGB TextureFilename Material MeshFace MeshMaterialList MeshTextureCoords MeshNormals Mesh ・座標変換に必要なテンプレート FrameTransformMatrix Frame ・アニメーションに必要なテンプレート FloatKeys TimedFloatKeys AnimationKey Animation AnimationSet ・スキンに必要なテンプレート VertexDuplicationIndices XSkinMeshHeader SkinWeights ・あると便利なテンプレート AnimTicksPerSecond |
|
|
|
|
|
|
|
|