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

フォローする

まとめ

ジオメトリが繰り返されるシーンでは、インスタンス化を使用すると、メモリ フットプリントが削減され、シーン グラフ クックのパフォーマンスが向上します。通常、インスタンス化は、ジオメトリが多くのコピー間で同じであり、必要な変更が変換だけである場合にうまく機能します。この記事では、「リーフレベル インスタンス化」と呼ばれるインスタンス ID 属性を使用したインスタンス化の方法について説明し、それを使用してジオメトリを点群の点にインスタンス化する方法の例を示します。

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

点群インスタンス化に関する以下のセクションを示すサンプル プロジェクトについては、Katana プロジェクト ファイル「 PointcloudInstancingAndmaterialAssign_Arnold.katana 」を参照してください。

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

次のセクションでは、リーフレベルのインスタンス化の概要を説明します。インスタンス化のより詳細な説明については、 Renderman ドキュメント: RenderMan 25 Docs - Instancing in Katanaで、インスタンス化の入門として 3 つのインスタンス化メソッドすべてを設定する方法が説明されています。

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

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

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

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

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

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

1. Alembic_In を使用して点群とインスタンス ソースをインポートします。次に、 instance.IDという属性を点群の位置の任意の文字列値に設定します。この例では、 instance.IDは「bob」です。

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 の場所の下にあります。

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

参考文献
インスタンス化の概要については、以下の最初のリソース リンクを参照してください。以下の他のリソースでは、各インスタンス化方法に関するその他の高度なインスタンス化トピックについて詳しく説明します。

添付ファイル

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

理由をお聞かせください