Q100517: リーフレベル(インスタンスID)インスタンス化によるシーングラフのクックパフォーマンスの向上

まとめ

繰り返しジオメトリを含むシーンでは、インスタンス化を使用することでメモリ使用量を削減し、シーングラフのクックパフォーマンスを向上させることができます。一般的に、インスタンス化は、ジオメトリが複数のコピー間で同一であり、必要な変更がトランスフォームのみである場合に有効です。この記事では、リーフレベルインスタンス化と呼ばれるインスタンスID属性を用いたインスタンス化の手法について説明し、ポイントクラウドのポイントにジオメトリをインスタンス化する例を示します。

利用可能なその他のインスタンス化アプローチの概要については、 Katana開発者ガイドの「インスタンス化」セクションをお読みください

ポイント クラウドのインスタンス化に関する以下のセクションを説明するサンプル プロジェクトについては、Katana プロジェクト ファイル「 PointcloudInstancingAndMaterialAssign_Arnold.katana 」を参照してください

リーフレベルのインスタンス化

以下のセクションでは、リーフレベルのインスタンス化について簡単に説明します。インスタンス化に関するより詳細な説明については、 Rendermanドキュメントをご覧ください。RenderMan 26 Docs - Instancing in Katanaインスタンス化入門として、3つのインスタンス化手法すべてを設定する方法が示されています。

リーフレベルのインスタンス化では、既存の繰り返しジオメトリをインスタンス化できます。つまり、シーン内に既に複数存在するジオメトリは一度だけロードされ、それ以降に同じジオメトリが出現する場合は、メモリ内の同じジオメトリデータセットを参照します。繰り返しジオメトリを含む既存のKatanaプロジェクトでインスタンス化のメリットを享受したい場合は、シーングラフ内の繰り返しジオメトリの場所にinstance.ID属性を追加することで簡単に変更できます。ただし、子要素のない場所しかインスタンス化できないという欠点があります。

これを実現するには、すべての同一の場所に一致するinstance.ID属性が必要です。レンダラーによってインスタンスソースとして1つの場所が選択され、他のすべての場所はその場所のインスタンスとして扱われます。

注:インスタンスソースとしてジオメトリがどのように選択されるかを理解することは、すべての場所にジオメトリを含める必要があるのか、それともシーングラフの最上位の場所だけにジオメトリが必要なのかを判断する上で非常に重要です。インスタンスソースの選択方法については、レンダラーのドキュメントを参照してください。

ポイントクラウドへのリーフレベルのインスタンス化

インスタンスIDを使用してポイントクラウドにインスタンス化するには、インスタンスソースをポイントクラウドの各ポイントにコピーするためのOpScriptが必要です。より簡単な解決策は、OpScriptを使用せずに階層インスタンス化を使用することです( Q100508:階層(インスタンスソース)インスタンス化によるシーングラフのクックパフォーマンスの向上を参照)。ただし、どちらのインスタンス化方法でもOpScriptを使用する利点は、個々のインスタンスの位置がビューアに表示されることと、各インスタンスに個別にマテリアルを割り当てることができることです。潜在的な欠点は、特にインスタンスが数千個ある場合、シーングラフがやや扱いにくくなることです。

OpScriptはインスタンスの位置を生成し、点群内の各点のinstance.ID属性をコピーします。OpScriptによって位置が生成されると、レンダラーは1つの位置をジオメトリソースとして選択し、他のすべての位置はその位置のインスタンスとして扱われます。以下は、点群のリーフレベルのインスタンス化を実現する手順です。

1. Alembic_In を使用して、ポイントクラウドとインスタンスソースをインポートします。次に、 instance.IDという属性に、ポイントクラウドの位置を表す任意の文字列値を設定します。この例では、 instance.IDbobに設定されています。

2. OpScriptノードを作成し、その場所パラメータを、インスタンスが生成されるシーングラフの場所に設定します。例: /root/world/geo/derivedassets

3. OpScriptノードで、 user.instanceSourceLocationパラメータを作成し、インスタンスソースのシーングラフ上の位置を設定します。次に、ポイントクラウドのシーングラフ上の位置を指定するuser.pointCloudLocationパラメータを作成します。ユーザーパラメータの作成手順については、 Katana ユーザーガイド「ユーザーパラメータの追加」を参照してください。リーフレベルのインスタンス化では、インスタンスソースの位置に子を含めることはできません。子を含めるとインスタンス化が機能しません。

4. 次に、次のコードを OpScript ノードのスクリプトパラメータにコピーして、ポイント クラウド内の各ポイントのインスタンスの場所を生成します。

 -- Read op arguments
local instanceSourceLocation = Interface.GetOpArg( "user.instanceSourceLocation" ):getValue()
local pointCloudLocation = Interface.GetOpArg( "user.pointCloudLocation" ):getValue()

if Interface.AtRoot() then
 
-- Read the point cloud
 
local points = Interface.GetAttr( "geometry.point.P" , pointCloudLocation):getNearestSample(Interface.GetCurrentTime())

 
-- Read the instanceID
 
local instanceID = Interface.GetAttr( "instance.ID" , pointCloudLocation):getNearestSample(Interface.GetCurrentTime())

 
-- Loop over points
 
local x, y, z
 
local gb = GroupBuilder()
 
for i= 0 , #points/ 3 - 1 do
      x = points[
3 *i+ 1 ]
      y = points[
3 *i+ 2 ]
      z = points[
3 *i+ 3 ]

     
-- Build op arguments for the child location
      gb:update(Interface.GetOpArg())
      gb:set(
"childAttrs" , Interface.GetAttr( "" , instanceSourceLocation))
      gb:set(
"childAttrs.geometry.instanceSource" , StringAttribute(instanceSourceLocation))
      gb:set(
"childAttrs.xform.interactive.translate" , DoubleAttribute({x, y, z}))
      gb:set(
"childAttrs.instance.ID" , StringAttribute(instanceID))

     
-- Create the child
      Interface.CreateChild(
         
string . format ( "child%04d" , i),
          Interface.GetOpType(),
          gb:build())
 
end
else
 
local childAttrs = Interface.GetOpArg( "childAttrs" )
 
for i= 0 , childAttrs:getNumberOfChildren() -1 do
      Interface.SetAttr(childAttrs:getChildName(i), childAttrs:getChildByIndex(i))
 
end
end

上記の OpScript は、 instance.ID属性を含むインスタンス ソースをポイント クラウド内の各ポイントにコピーします。

5. 最後に、Pruneノードを使用してシーングラフからポイントクラウドを削除し、レンダリングから除外します。この手順は、ポイントクラウドがレンダラーによってインスタンスソースとして選択されないようにするために必要です。

マテリアル割り当てによるマテリアルバリエーション

インスタンスごとにマテリアルを変更すると、すべてのインスタンスがインスタンスソースのプロパティ(マテリアルなど)を継承するため、余分な作業が発生する可能性があります。このセクションでは、インスタンス化によるパフォーマンス上のメリットを維持しながら、インスタンスごとにマテリアルとシェーダーを変更する方法について説明します。

OpScript によるリーフ レベルおよび階層的なインスタンス化を使用してポイント クラウド上の各ポイントのインスタンスの場所を作成すると、インスタンスの場所ごとにマテリアルを割り当てることができるという利点があります。

インスタンスの位置を生成したら、各インスタンスの位置ごとにマテリアルを変更できます。特定のインスタンスを識別するには、シーングラフでインスタンスの位置を展開し、ビューアで目的のインスタンスを選択するだけです。提供されているサンプルプロジェクトでは、インスタンスの位置は/root/world/geo/derivedassets配下にあります。

その後、MaterialAssign ノードを使用するか、インスタンスの場所にmaterialAssign属性を設定してマテリアルの場所を指定することにより、マテリアルを目的の場所に割り当てることができます。

さらに詳しく
インスタンス化の概要については、下記の最初のリソースリンクをご覧ください。その他のリソースでは、各インスタンス化手法における高度なインスタンス化のトピックについて詳しく説明されています。

添付ファイル

私たちはそれを聞いて申し訳ございません

理由をお聞かせください