Q100517: Increasing scene graph cook performance with Leaf-level (Instance ID) Instancing

Follow

SUMMARY

In any scene with repeating geometry, instancing can be used for the benefit of a reduced memory footprint and increased scene graph cook performance. Typically, instancing works well when the geometry is the same across many copies and the only modifications required are transformations. This article describes a method of instancing using the instance ID attribute called “leaf-level instancing”, giving an example of how to use it to instance geometry to points of a point cloud.

For an overview on other available instancing approaches, please read the following section in the Katana Developer Guide: Instancing.

Please refer to the Katana project file “PointcloudInstancingAndMaterialAssign_Arnold.katana” for an example project illustrating the sections below on point cloud instancing.

 

Leaf-level instancing

The following section is a brief overview of leaf-level instancing. For a more in-depth discussion to instancing, the Renderman Documentation: RenderMan 26 Docs - Instancing in Katana demonstrates how to set up all three instancing methods as introduction to instancing.

In leaf-level instancing, pre-existing repeating geometry can be instanced, meaning that geometry that already exists multiple times in the scene will only be loaded once and any additional occurrences of the geometry will reference the same set of geometry data in memory. Existing Katana projects with repeating geometry that would benefit from instancing can be easily modified by adding a instance.ID attribute to repeating geometry locations in the scene graph. A draw-back, however, is that only locations with no children can be instanced.

To achieve this, all identical locations should have a matching instance.ID attribute. One location is selected as the instance source by the renderer, then all other locations are treated as instances of that location.

NOTE: Understanding how geometry is selected as the instance source is crucial to decide if all locations need to contain geometry or if only the highest location in the scene graph needs geometry. Please refer to the renderer documentation to understand how the instance source is selected.

 

Leaf-Level Instancing to a point cloud

Using Instance IDs for instancing to a point cloud requires an OpScript to copy an instance source to each point of a point cloud. A simpler solution is to use hierarchical instancing without the need for an OpScript (see Q100508: Increasing scene graph cook performance with Hierarchical (Instance Source) Instancing). However, the benefit of using an OpScript for either instancing method is that the individual instance locations are visible in the Viewer and materials can be assigned separately to each instance. A potential drawback is a slightly more unwieldy scene graph, especially if there are thousands of instances.

The OpScript generates an instance location and copies the instance.ID attribute for each point in the point cloud. Once the locations are generated by an OpScript, the renderer selects one location as the geometry source then all other locations are treated as instances of that location. The following are steps to achieve leaf-level instancing to a point cloud.

 

1. Import a point cloud and the instance source using Alembic_In. Then set an attribute called instance.ID to an arbitrary string value on the point cloud location. In this example, instance.ID is “bob”.

 

2. Create an OpScript node and set its location parameter to a scene graph location under which instances will be generated, for example: “/root/world/geo/derivedassets”

 

3. In the OpScript node, create a user.instanceSourceLocation parameter and set it to the scene graph location of the instance source. Then create a user.pointCloudLocation parameter to the point cloud’s scene graph location.  For steps on creating user parameters, see the Katana User Guide: Adding User Parameters. Please note that in leaf-level instancing, the instance source location cannot contain children otherwise instancing will not work.

 

4. Then copy the following code into the OpScript node's script parameter to generate instance locations for each point in the point cloud.

-- 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

The above OpScript copies the instance source to each point in a point cloud, including the instance.ID attribute.

 

5. Lastly, use a Prune node to remove the point cloud from the scene graph to omit it from the render. This step is necessary so that the point cloud is not selected as an instance source by the renderer.

 

Material Variation with Material Assign

Modifying the material per-instance can pose some extra work as all instances inherit the properties of the instance source such as the material. This section will explain a method to vary the material and shader per instance while maintaining the performance benefits of instancing.

Using leaf-level and hierarchical instancing with an OpScript to create instance locations for each point on point clouds has the benefit that materials can be assigned per instance location.

After generating the instance locations, the materials can be varied per location of each instance. Identifying specific instances is as simple as expanding the instance locations in the Scene Graph and selecting the desired instance in the Viewer. In the provided example project, the instance locations can be found underneath the /root/world/geo/derivedassets location.

A material can then be assigned to the desired locations using a MaterialAssign node or by setting a materialAssign attribute on the instance location, pointing to the material location.

 

FURTHER READING
For an instancing overview, see the first resource link below. The other resources below go in-depth on other advanced instancing topics on each instancing method.

 

ATTACHMENTS

We're sorry to hear that

Please tell us why