XSIのシーンからデータを抽出する2

今回はマテリアルとUVに関してです。
結構複雑なので、まだ色々と対応出来ていない事や抜けがあるかもしれませんが、
ひとまず最低限描画に必要な物を抜き出してみます。

まずはマテリアル(Materialクラス)を取得する方法です。
シーンに含まれている全てのマテリアルを一覧するだけなら以下の方法で可能です。

{
    Application app;
    Project project = app.GetActiveProject();
    Scene   scene   = project.GetActiveScene();

    MaterialLibrary matlib = scene.GetActiveMaterialLibrary();
    CRefArray materials = matlib.GetItems();
    for( LONG i = 0 ; i < materials.GetCount() ; ++i ){
        Material material( materials[ i ] );
    }
}


ただ、このやり方ではどのメッシュとマテリアルが組み合わせられるのか分かりません。
それを解決するには以下の方法でマテリアルを取得します。

void Func( const X3DObject& obj )
{
    // まずはクラスターに対して適用されているマテリアルを探す
    CRefArray primitives = obj.GetPrimitives();
    for( LONG i = 0 ; i < primitives.GetCount() ; ++i ){
        Primitive primitive( primitives[ i ] );
        Geometry geometry = primitive.GetGeometry();
        if( geometry.IsA( siPolygonMeshID ) ){
            PolygonMesh mesh( geometry );
            CRefArray clusters = mesh.GetClusters();

            CLongArray polygon_indices;
            for( LONG i = 0 ; i < clusters.GetCount() ; ++i ){
                Cluster cluster = clusters[ i ];
                Material material = cluster.GetMaterial();
                if( material.IsValid() == false ){
                    continue;
                }
                …  // マテリアルに関する処理
            }
        }
    }

    // クラスターに対して適用されているマテリアルが無い場合はオブジェクトから探す
    CRefArray materials  = obj.GetMaterials();
    if( materials.GetCount() > 0 ){
        for( LONG i = 0 ; i < materials.GetCount() ; ++i ){
            material = materials[ i ];
            …  // マテリアルに関する処理
        }
    }
    else{
        // オブジェクトに適用されている物が無ければシーンのマテリアルを使用する
        Application app;
        Project project = app.GetActiveProject();
        Scene   scene   = project.GetActiveScene();

        MaterialLibrary matlib = scene.GetActiveMaterialLibrary();
        CRefArray materials = matlib.GetItems();
        for( LONG i = 0 ; i < materials.GetCount() ; ++i ){
            material = materials[ i ];
            …  // マテリアルに関する処理
        }
    }
}


次にMaterialからD3DMATERIAL9のメンバと対応するデータを抜き出します。
シェーダはまた複雑ですが、ひとまず”Phong”と言う名前のシェーダだけを抜き出します。

{
    CRefArray shaders = material.GetShaders();
    D3DMATERIAL9 d3d_material;

    for( LONG j = 0 ; j < shaders.GetCount() ; ++j ){
        Shader shader( shaders[ j ] );
        if( shader.GetName() == L"Phong" ){
            float r, g, b, a;
            if( shader.GetColorParameterValue( L"ambient", r, g, b, a ) == CStatus::OK ){
                d3d_material.Ambient.r = r;
                d3d_material.Ambient.g = g;
                d3d_material.Ambient.b = b;
                d3d_material.Ambient.a = a;
            }
            {
                Parameter param = shader.GetParameter( L"diffuse_inuse" );
                CValue    value = param.GetValue();
                bool      inuse = value;
                if(
                    ( inuse ) &&
                    ( shader.GetColorParameterValue( L"diffuse", r, g, b, a ) == CStatus::OK )
                ){
                    d3d_material.Diffuse.r = r;
                    d3d_material.Diffuse.g = g;
                    d3d_material.Diffuse.b = b;
                    d3d_material.Diffuse.a = a;
                }
            }
            {
                Parameter param = shader.GetParameter( L"specular_inuse" );
                CValue    value = param.GetValue();
                bool      inuse = value;
                if(
                    ( inuse ) &&
                    ( shader.GetColorParameterValue( L"specular", r, g, b, a ) == CStatus::OK )
                ){
                    d3d_material.Specular.r = r;
                    d3d_material.Specular.g = g;
                    d3d_material.Specular.b = b;
                    d3d_material.Specular.a = a;

                    param = shader.GetParameter( L"shiny" );
                    value = param.GetValue();
                    float shiny = value;
                    d3d_material.Power = shiny; // 本当はこの値は加工しないといけない
                }
            }
            if( shader.GetColorParameterValue( L"ambience", r, g, b, a ) == CStatus::OK ){
                d3d_material.Emissive.r = r;
                d3d_material.Emissive.g = g;
                d3d_material.Emissive.b = b;
                d3d_material.Emissive.a = a;
            }
        }
    }
}


次にテクスチャの情報を取得します。
と言ってもひとまずファイル名だけです。

{
    ImageClip2 image_clip = material.GetCurrentImageClip2();
    CString file_name = image_clip.GetFileName();
}


最後にUV情報を取得します。

void Func( const PolygonMesh& mesh, const X3DObject& obj )
{
    CVertexRefArray      vertices  = mesh.GetVertices();  // 頂点データ
    CPolygonFaceRefArray polygons  = mesh.GetPolygons();  // 面データ
    CRefArray            clusters  = mesh.GetClusters();

    // まずクラスターから取得する
    CLongArray polygon_indices;
    for( LONG i = 0 ; i < clusters.GetCount() ; ++i ){
        Cluster  cluster  = clusters[ i ];
        Material material = cluster.GetMaterial();
        if( material.IsValid() == false ){
            continue;
        }

        ClusterProperty property = material.GetCurrentUV();
        CFloatArray     uvs;
        property.GetValues( uvs );

        for( LONG j = 0 ; j < elements.GetCount() ; ++j ){
            LONG element = elements.GetItem( j );
            PolygonFace polygon          = polygons[ element ];
            CLongArray  triangle_indices = polygon.GetTriangleSubIndexArray();
            CLongArray  vertex_indices   = polygon.GetVertices().GetIndexArray();
            CLongArray  node_indices     = polygon.GetNodes().GetIndexArray();
            for( LONG k = 0 ; k < triangle_indices.GetCount() ; ++k ){
                LONG vertex_index = vertex_indices[ triangle_indices[ k ] ];
                LONG uv_index     = node_indices[ triangle_indices[ k ] ];

                // 頂点情報
                bool is_normal_valid;
                Vertex vertex = vertices[ vertex_index ];
                MATH::CVector3 p = vertex.GetPosition();
                MATH::CVector3 n = vertex.GetNormal( is_normal_valid );
                float u = uvs[ ( uv_index * 3 ) + 0 ];
                float v = uvs[ ( uv_index * 3 ) + 1 ];
                float w = uvs[ ( uv_index * 3 ) + 2 ];
            }
            polygon_indices.Add( element );     // クラスターが適用されているポリゴンを保存しておく
        }
    }

    // クラスターが適用されていないポリゴン
    {
        Material  material;
        CRefArray materials = obj.GetMaterials();
        if( materials.GetCount() > 0 ){
            material = materials[ 0 ];
        }
        else{
            // オブジェクトに適用されている物が無ければシーンのマテリアルを使用する
            Application app;
            Project project = app.GetActiveProject();
            Scene   scene   = project.GetActiveScene();

            MaterialLibrary matlib = scene.GetActiveMaterialLibrary();
            CRefArray materials = matlib.GetItems();
            if( materials.GetCount() > 0 ){
                material = materials[ 0 ];
            }
        }

        if( material.IsValid() == false ){
            return;
        }

        for( LONG i = 0 ; i < polygons.GetCount() ; ++i ){

            ClusterProperty property = material.GetCurrentUV();
            CFloatArray     uvs;
            property.GetValues( uvs );

            bool is_registered = false;
            for( LONG j = 0 ; j < polygon_indices.GetCount() ; ++j ){
                if( i == polygon_indices[ j ] ) { is_registered = true; }
            }
            if( is_registered ) { continue; }

            PolygonFace polygon = polygons[ i ];
            CLongArray  triangle_indices = polygon.GetTriangleSubIndexArray();
            CLongArray  vertex_indices   = polygon.GetVertices().GetIndexArray();
            CLongArray  node_indices     = polygon.GetNodes().GetIndexArray();
            for( LONG k = 0 ; k < triangle_indices.GetCount() ; ++k ){
                LONG vertex_index = vertex_indices[ triangle_indices[ k ] ];
                LONG uv_index     = node_indices[ triangle_indices[ k ] ];

                bool is_normal_valid;
                Vertex vertex = vertices[ vertex_index ];
                MATH::CVector3 p = vertex.GetPosition();
                MATH::CVector3 n = vertex.GetNormal( is_normal_valid );
                float u = uvs[ ( uv_index * 3 ) + 0 ];
                float v = uvs[ ( uv_index * 3 ) + 1 ];
                float w = uvs[ ( uv_index * 3 ) + 2 ];
            }
        }
    }
}


上記の方法以外にも以下のようにTriangleクラスを使用する方法もありそうですが、
そっちの検証はまた後日にしたいと思います。

{
    CTriangleRefArray triangles = mesh.GetTriangles();
    for( LONG i = 0 ; i < triangles.GetCount() ; ++i ){
        Triangle triangle = triangles[ i ];
    }
}


この情報をプロジェクトに組み込んで表示させてみました。
exporter01
無事テクスチャが表示されました。

次はスキニングメッシュの為の骨構造とウェイトです。

コメント/トラックバック (1件)

  1. ぱふぅ家のサイバー小物 のコメント:

    【冷却性と拡張性を重視】PCケース「ElementS with Mesh Window」

    2.5インチSSDも標準搭載できる、冷却性と拡張性を重視したATX/microATXマザー対応のミドルタワーPCケースだ。

コメントする

post date*

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

トラックバックする

トラックバック用URL:

アニメーションが親切に解説されております

レンダリング、ライティングの基本が分かります

図版が見やすい美術解剖書です