XSIのシーンからデータを抽出する3
今回はマトリクスとウェイトデータに関してです。
まずはマトリクスを取得します。
void Func( const X3DObject& obj ) { MATH::CMatrix4 global = obj.GetKinematics().GetGlobal().GetTransform().GetMatrix4(); MATH::CMatrix4 local = obj.GetKinematics().GetLocal().GetTransform().GetMatrix4(); CString name = obj.GetName(); CRefArray children = obj.GetChildren(); for( LONG i = 0 ; i < children.GetCount() ; ++i ){ X3DObject child( children[ i ] ); Func( child ); } } { Project project = app.GetActiveProject(); Scene scene = project.GetActiveScene(); Model root = scene.GetRoot(); Func( root ); }
こんな感じでルートから再帰的に末端までのマトリクスを取得していきます。
ちなみにDirectXは左手系、XSIは右手系の座標系なので、
マトリクスも変換しなくてはいけません。
void ConvertMatrix( D3DXMATRIX& dst, const MATH::CMatrix4& src ) { double d00, d01, d02, d03; double d10, d11, d12, d13; double d20, d21, d22, d23; double d30, d31, d32, d33; src.Get( d00, d01, d02, d03, d10, d11, d12, d13, d20, d21, d22, d23, d30, d31, d32, d33 ); dst._11 = static_cast< float >( d00 ); dst._12 = static_cast< float >( d01 ); dst._13 = static_cast< float >( -d02 ); dst._14 = static_cast< float >( d03 ); dst._21 = static_cast< float >( d10 ); dst._22 = static_cast< float >( d11 ); dst._23 = static_cast< float >( -d12 ); dst._24 = static_cast< float >( d13 ); dst._31 = static_cast< float >( -d20 ); dst._32 = static_cast< float >( -d21 ); dst._33 = static_cast< float >( d22 ); dst._34 = static_cast< float >( d23 ); dst._41 = static_cast< float >( d30 ); dst._42 = static_cast< float >( d31 ); dst._43 = static_cast< float >( -d32 ); dst._44 = static_cast< float >( d33 ); }
なぜこのようになるかは面倒なので説明は省きます。
きちんと幾何学を解説しているページを探してみてください。
ちなみにベクトルもZ要素(厳密にはZとは限りませんが)の符号を反転する必要があります。
次にウェイトデータの取得方法です。
ウェイトデータもマテリアルの時のようにClusterクラスからアクセスします。
void Func( const PolygonMesh& mesh ) { CRefArray clusters = mesh.GetClusters(); CStringArray deformer_names; for( LONG i = 0 ; i < clusters.GetCount() ; ++i ){ Cluster cluster = clusters[ i ]; CRefArray envelopes = cluster.GetEnvelopes(); for( LONG j = 0 ; j < envelopes.GetCount() ; ++j ){ Envelope envelope = envelopes[ j ]; CRefArray deformers = envelope.GetDeformers(); for( LONG k = 0 ; k < deformers.GetCount() ; ++k ){ X3DObject deformer = deformers[ k ]; deformer_names.Add( deformer.GetName() ); } CClusterPropertyElementArray weights = envelope.GetWeights( 0 ); if( weights.GetCount() == 0 ){ continue; } for( LONG k = 0 ; k < weights.GetCount() ; ++k ){ CDoubleArray items = weights.GetItem( k ); unsigned int num = 0; unsigned int deformer_indices = 0; float weight[ 4 ] = 0.0f; for( int index = 0 ; index < items.GetCount() ; ++index ){ // 1頂点につきウェイト付けできるマトリクスは4つまでにしておく if( ( items[ index ] > 0.0f ) && ( num < 4 ) ){ deformer_indices |= ( ( 0x000000ff & index ) << ( num * 8 ) ); // 1byte毎にマトリクスのインデックスを格納する weight[ num ] = static_cast< float >( items[ index ] * 0.01 ); // DirectXでは0.0 ~ 1.0 なので 100 で割る ++num; } } } } } }
このようにdeformer(ウェイト付けされるオブジェクト)の名前と
どのdeformaerにウェイト付けされるかのインデックスを4byteの変数に格納したものと、
どのdeformaerに何%づつウェイト付けされているかの数値を取っておきます。
DirectXの固定機能パイプラインでは変換マトリクスは256個まで、
ウェイト付けできるマトリクスは1頂点につき4つまでなので、
上記のコードのようになります。
大分説明が足りていない気がしますが、これで一応必要なデータは揃いました。
これをプロジェクトに組み込んで見たのがこれです。
見た目では分かりませんが、ちゃんとスキニングされています…
DirectXでスキンメッシュを表示させる方法はきちんと説明が必要かと思いますが、
とりあえず今回はプラグインの話なので割愛します。
次にアニメーションを実装してプラグインの話はひと段落して、
その時点でソースをまとめて公開したいと思います。
コメントする
トラックバックする
トラックバック用URL: