ジオメトリを用いた空間分析群(Spatial queries)の使用

空間分析群はジオメトリックポジションに基づいて検索を行う一連の操作です。一般的な空間分析群には、線交点の発見( ‘raycast’ )、最も近いサーフェースの発見( ‘getClosest’ )またはスフィアのようなボリュームとの交差を検索することが含まれます。 SpatialQueryable インターフェースは PolygonMeshLinesPoints といったような Geometry 型で様々な空間分析を実行することができます。

同じジオメトリ上で複数の空間分析が実行されるとき、高速化構造はパフォーマンスを大きく向上できます。 Geometry 型を組み込んだ SpatialQueryable の実行は内部に高速化構造をキャッシュできます。高速化構造は分析を実行する前に更新し適切に準備する必要があります。詳細については 高速化構造 を参照してください。

注釈

ジオメトリ上での空間分析の実行は、ジオメトリの変更が無く、 SpatialQueryable.prepareForSpatialQueries かもしくは SpatialQueryable.removeSpatialQueryAcceleration の呼び出しがない場合に限りスレッドセーフです。
/*
** Example: Performing a simple shrink wrap deformer using SpatialQueryable
*/

require Geometry;

operator ParallelShrinkWrap<<<index>>>( io PolygonMesh source, SpatialQueryable target ) {
  Ray ray;
  ray.start = source.getPointPosition( index );
  ray.direction = -ray.start.unit();//Unit vector toward sphere's center

  GeometryLocation location = target.raycast(ray, true, 0.0, SCALAR_INFINITE);
  if( location.isValid() )
    source.setPointPosition( index, target.getPositionAtLocation( location ) );
  else
    report("Unexpected: no hit");
}

operator entry(){
  //Shrink wrap a sphere onto a cylinder
  PolygonMesh source(), target();
  source.addSphere(Xfo(), 10.0, 3, true, false);

  //Cylinder (Y from -2.0 to 2.0)
  target.addCylinder(Xfo(), 4.0, 4.0, true, 16, 16, true, false);

  //Initialize options to use a sparse grid
  GenericValueContainer options = GenericValueContainer();
  PrepareForSpatialQueries_setSparseGrid(options);

  //Prepare for one query per source point
  target.prepareForSpatialQueries( source.pointCount(), options );

  report("Point 0 initial position: " + source.getPointPosition(0));
  ParallelShrinkWrap<<<source.pointCount()>>>( source, target );
  report("Point 0 deformed position: " + source.getPointPosition(0) );
}

/*
** Output:

Point 0 initial position: {x:+0.0,y:+10.0,z:+0.0}
Point 0 deformed position: {x:-1.685873e-7,y:+2.0,z:+1.685874e-7}

*/

空間分析(SpatialQuery)オブジェクトの使用

SpatialQuery.getElementsInBBox のような幾つかの分析は SpatialQuery オブジェクト経由でのみアクセス可能です。 SpatialQuery オブジェクトは SpatialQueryable.beginSpatialQuery を呼び出すことで取得し、 SpatialQueryable.endSpatialQuery の呼び出しによって解放されるまで一時的に使用される必要があります。

SpatialQuery オブジェクトが有効な状況は..

注釈

SpatialQuery オブジェクトは1つまたは複数の分析を効率的に実行するために必要なスレッド固有の一時記憶を保持します。これらのオブジェクト群は、パフォーマンスの向上のために内部でリサイクルされます。

SpatialQueryable.beginSpatialQuery の呼び出しはスレッド セーフですが、返された SpatialQuery オブジェクトはそうではありません (ローカルのみで使用すべきです)。

次の例では、 SpatialQuery の適切なマルチ スレッドの使用法を説明します。

require Geometry;

operator ParallelBBoxSearch<<<index>>>( Ref<SpatialQueryable> target, io Boolean intersectsElementsBBox[10] ) {
  //Allocate a temporary query object
  Ref<SpatialQuery> query = target.beginSpatialQuery();

  Size elementCount = query.getElementsInBBox( Vec3(0, index, 0), Vec3(1, index+1, 1) );
  if( elementCount )
    intersectsElementsBBox[index] = true;

  //Release temporary query object
  target.endSpatialQuery(query);
}

operator entry(){
  //Check which unit bboxes with Y = 0..9 intersect the surface of a sphere of radius 5.0
  PolygonMesh target();
  target.addSphere(Xfo(), 5.0, 3, true, false);

  Boolean intersectsElementsBBox[10];
  target.prepareForSpatialQueries( 10, null );

  ParallelBBoxSearch<<<10>>>( target, intersectsElementsBBox );
  report("Intersected bounding boxes:\n " + intersectsElementsBBox );
}

/*
** Output:

Intersected bounding boxes:
 [false,false,false,false,true,true,false,false,false,false]

*/

ジオメトリロケーション構造

SpatialQueryable.raycast のようなメソッド群において、分析結果はサーフェース上の特定のポイント(位置)を指し、 GeometryLocation 構造が返されます。 GeometryLocation メンバーの内容と意味は、下記の各 Geometry 型で特有です。

  • PolygonMesh:ポリゴンメッシュ
    • index はポリゴンインデックスを保存します
    • subIndex はポリゴンのサブ・トライアングル・インデックスを保存します。例えば、[4,5,6,7]頂点の四角形における[4,5,6]と[4,6,7]を頂点とする三角形に対し、各三角形への subIndex はそれぞれ0と1です。
    • barycentric は三角形の頂点に対する相対的ウェイト値を保存します。三角形は[a、b、c]のアトリビュート値に対応し、結果のアトリビュート値は (a * barycentric.x) + (b * barycentric.y) + (c * barycentric.z) の線形結合よって算出することができます。
  • Lines:ライン群
    • index は線分のインデックスを保存します。
    • barycentric.xy は線分の始点と終点それぞれへのウェイトを保存します。線分への始点・終点のアトリビュート値は[a,b]で、結果のアトリビュート値は (a * barycentric.x) + (b * barycentric.y) の線形結合で算出できます。
  • Points:ポイント群
    • index はポイントのインデックスを保存し、アトリビュートインデックスと同じです。
    • barycentric 適用可能な時に保存する可能性があり、normal はポイントと相対です。これはポイントが球体とみなされ大きさを持つとき、特定のサーフェース・ロケーションを維持することができます。

注釈

GeometryLocation は特定のジオメトリ、または同一の構造( topology )において有効です。 GeometryLocation は変形(アニメーション)中でも変動しません。

GetAttributeAtLocation ヘルパー関数群は GeometryLocation に対するアトリビュート値を返すことができます。これらは SpatialQueryable.getLocationAttributeIndicesAndWeights と、アトリビュートの getLinearCombination メソッドをシンプルに内包したものです。

高速化構造

空間分析は OctreeSparseGrid のような高速化構造の内部キャッシュを用いて実行できます。キャッシュされた高速化構造を持たない複数の分析を実行すると、特に複雑な形状において、非常に処理が遅くなることがあります。 SpatialQueryable インタフェースを通した高速化構造を適切に使用するために、いくつかのルールに従う必要があります。

内蔵のジオメトリ群( PolygonMesh , Lines , Points )は none(つまり持たない)、 OctreeSparseGrid のいずれかの高速化構造をサポートします。これらは SpatialQueryable.prepareForSpatialQueries オプションを使用して指定することができます。

高速化構造の初期設定は、あらゆる状況でうまく動作する Octree です。どちらの高速化構造も、増分の更新(小さな変更、小さな更新コスト)をサポートしています。これら高速化構造の比較は オクトリー(Octree ) vs スパースグリッド(SparseGrid) を参照してください。

SpatialQueryable.prepareForSpatialQueries メソッドは、後の分析(マルチスレッド可)の呼び出しを早めるために、高速化構造をインストールまたは更新します。もし SpatialQueryable.prepareForSpatialQueries が最初またはジオメトリの変更後に呼び出されていない場合、ジオメトリはアトリビュートや構造のバージョンの変更を検出すると高速化を無効化し、パフォーマンスの低下につながります。

注釈

SpatialQueryable.prepareForSpatialQueriesGeometry 型が変更された後に再び呼び出すとき、高速化構造は増分の更新を行います。これは高速化構造が性能を向上させるために、変化に一致するように一部分だけを変更することを意味します。サーフェースの変形はフレーム間では通常小さなものなので、これは再生中に特に役立ちます。

注釈

高速化構造は、コンパクトな配列の内部構成です。 unguarded モードでのKLコンパイルは、通常は空間分析を30%高速化します。

SpatialQueryable.removeSpatialQueryAcceleration は、加速構造を削除してメモリを解放できます。しかし、通常は(詳細については、メソッドの説明を参照)、このメソッドを呼び出すことをお勧めしません。

オクトリー(Octree ) vs スパースグリッド(SparseGrid)

ここでは OctreeSparseGrid を簡単に比較します。

  • メモリ:オクトツリーはスパースグリッドの約2倍のメモリを要します。しかし両方の構造は低いメモリ使用量に最適化されたとしても、それらはまだ顕著なメモリ量を必要とし、PolygonMesh構造で使用されるメモリに匹敵します。
  • スパースグリッドの構築と更新は、オクトリーよりも多くの場合で2倍以上高速です。
  • SpatialQuery.raycast: ジオメトリ・エレメント (ポリゴン、ポイント) が空間に比較的均一に分布する場合、スパースグリッドは約30%高速化することができますが、ジオメトリ・エレメントの密度が大幅に異なる場合は遅くなります。
  • SpatialQuery.getClosest: オクトリーは通常スパースグリッドよりもはるかに高速です。スパースグリッドは検索ポイントがジオメトリのサーフェスから離れている場合は特に遅くなります。
  • SpatialQuery.getElementsInBBoxSpatialQuery.getElementsInBSphere: 検索ボリュームがジオメトリ・エレメント間の距離に類似している場合や、ジオメトリ・エレメントが空間に比較的均一に分布している場合、スパースグリッドの方が速くなるでしょう。