HOOPS Visualizeによる3D InterOpからのグラフィカルなデータのレンダリング

日 9 23, 2018

最近、あるお客様から、Graphical 3D InterOpでCADファイルから変換した3Dビジュアライゼーションモデルをどのようにレンダリングするかを尋ねられました。(下記参照1)お客様はHOOPSを使用されているので、当社製品同士を接続するブリッジライブラリを使用することがすぐに思いつきました。まさにこの目的のための3D InterOp/HOOPsブリッジがあります。しかし私は、異なるコンポーネント間でどのようにデータが受け渡されるのかを知りたいと思いました。特に、少し前に使用した小さなテストアプリケーションがあったのですが、ブリッジで生成されたものと同じようには表示されませんでした。  (ブリッジは実際にはソースとして出荷されているので、見てみたい方はコードを入手することができます。)

最初に理解する必要があるのは、グラフィカル InterOpによって提供されるデータの形式でした。(ここでは、モデル内の面のレンダリング情報に絞ります。)モデルの各面は、三角形の集合体で表現されます。  このデータは、面の各頂点の位置、各頂点の法線、頂点の接続方法の記述で構成されています。

三角形は、頂点のインデックスによって頂点位置配列に記述され、三角形の単純なリストとして、またはTriStripsまたはTriFansとして最適化された形式で記述されます。

Triangles, TriStrips, TriFans

これはごく標準的なことであり、説明情報はInterOpのドキュメントにありますが、三角形をHOOPSにレンダリングする手順には、初期の試みで見落としていた微妙な点がいくつかあります。

最初に、HOOPSでシェルを作成したいと思ったのは、それらが三角形間の良好な連続性で優れたシェーディングとライティング効果をサポートするためですが、InterOpでは、面のデータは一連のTriangles、TriStrips、またはTriFansとして表示されます。 面全体に陰影を付けるには、これらを顔全体の単一のシェルに組み合わせる必要がありました。

2つ目は、これらのシェルを組み合わせることで、頂点の位置をHOOPS関数に提示するのは、三角形のセットごとではなく、面に対して一度だけになるので、実際に処理を効率化することができます。

3つ目は、TriStripsと同じ機能(HC_Insert_Shell_By_Tristrips)を使って、HOOPSにTriFansを挿入できることです。ただし、TriFanデータの頂点数を実際の頂点数からマイナスするように設定すれば、HOOPSはTriFanを正しく解釈します。  このように、HOOPSは内部的にはTriFanをサポートしていませんが、入力データとしてTriFanでシェルを定義することは可能です。

最後に、シェーディングのためにHOOPSは頂点の位置からシェルの法線ベクトルを計算することができますが、InterOpは実際のモデルから法線を提供してくれています。  InterOp社の法線を使うことで、面の境界での連続性が向上します。

これらを考慮して、私はデータをHOOPSデータベースに取り込むためのコードを書きました。

// Iterate through the triangle sets in the face
std::vector<int> face_list_indices;
SPAIopVisuPolygonIter polygon_iterator = currentFace.GetPolygonIterator();
while( polygon_iterator.Next())
{
  // Get the current triangle set
  SPAIopVisuPolygon current_polygon = polygon_iterator.Current();
  SPAIopVisuPolygonType polygonType( SPAIopVisu_PolygonType_Unknown );
  const int* p_polygon_indices = NULL;
  int polygon_index_count = current_polygon.GetPolygonIndices(p_polygon_indices, polygonType );
  int polygon_index;
  switch ( polygonType )
  {
  case SPAIopVisu_PolygonType_Triangle:
    for ( polygon_index=0; polygon_index<polygon_index_count/3; polygon_index++ )
    {
      face_list_indices.push_back(3);
      // divide by 3 as HOOPS indexes by point (i.e. 3 floats)
      face_list_indices.push_back(p_polygon_indices[polygon_index*3]/3);
      face_list_indices.push_back(p_polygon_indices[polygon_index*3+1]/3);
      face_list_indices.push_back(p_polygon_indices[polygon_index*3+2]/3);
    }
    break;
  case SPAIopVisu_PolygonType_TriStrip:
    face_list_indices.push_back(polygon_index_count);
    for ( polygon_index=0; polygon_index<polygon_index_count; polygon_index++ )
    {
      // divide by 3 as HOOPS indexes by point (i.e. 3 floats)
      face_list_indices.push_back(p_polygon_indices[polygon_index]/3);
    }
    break;
  case SPAIopVisu_PolygonType_TriFan:
    face_list_indices.push_back(-polygon_index_count);    // Negative for TriFan
    for ( polygon_index=0; polygon_index<polygon_index_count; polygon_index++ )
    {
      // divide by 3 as HOOPS indexes by point (i.e. 3 floats)
      face_list_indices.push_back(p_polygon_indices[polygon_index]/3);
    }
    break;
  }
}

// Get the face points and normals
const float* p_face_vertices = NULL;
int face_vertex_count = currentFace.GetVertices( p_face_vertices );
const float* p_face_normals = NULL;
int face_normal_count = currentFace.GetNormals( p_face_normals );

// Create the shell
HC_KEY shell_key = HC_Insert_Shell_By_Tristrips (face_vertex_count, p_face_vertices,
face_list_indices.size(), face_list_indices.data(), 0, NULL);
HC_MSet_Vertex_Normals(shell_key, 0, face_normal_count, p_face_normals);

外観を改善するために、鏡面ハイライト効果で面全体の色を滑らかに補間するフォンシェーディングを使用しました。これは、フォンシェーディングアルゴリズムで、三角形全体の法線ベクトルを補間することによって実現されます。これも、InterOpから提供した法線情報を利用します。 このオプションは、モデルを保持するメインのHOOPSセグメントに設定しました。

このコードを使ってレンダリングされたデモパーツの1つをご紹介します。

Spatial Rendered Part

結論として、私は生成した画像に満足しています。私が書いたコードは単純で、実際には最初の試みよりもデータの点で効率的でした。 ただし、はるかに迅速な実装としてブリッジコードを使用することをお勧めします。

Subscribe to the D2D Blog

No Comments Yet

Let us know what you think