Q100514: Instance Array Instancing
Warning: This article contains links to external websites
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 “instance array” locations, 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 Q100518: Instancing Overview.
Please refer the Katana project file “instanceArray_arnold_material.katana” for an example project illustrating the sections below on point cloud instancing.
Instance Arrays
The following section is a brief overview of array instancing. For a more in-depth discussion to instancing, the Renderman Documentation: RenderMan 22 Docs - Instancing in Katana demonstrates how to set up all three instancing methods as an introduction to instancing.
In instance arrays, instance locations are mapped to one or more instance sources via attributes on a single location of type “instance array”. Instance arrays are similar to hierarchical instancing, with the added benefit of an easy way to set up multiple instance sources. One drawback is that materials cannot be varied per instance.
The instance array location needs to contain the geometry.instanceSource and at least one transformation attribute. The geometry.instanceIndex is optional if instanceSource contains a single path only, in which case that instance source is used for all instances in the instance array.
geometry.instanceSource |
String or string array attribute containing scene graph location paths of one or more instance sources |
geometry.instanceIndex |
Array attribute with the same number of elements as instances required. The values stored in this array indicate the index of the desired instance source in the geometry.instanceSource array. In other words, instanceIndex constitutes a mapping from instance index to instance source index. |
geometry.instanceMatrix geometry.instanceTranslate geometry.instanceRotateX geometry.instanceRotateY |
Each attribute is a flat array of per-instance transformations. The meaning of each attribute is the same as for conventional transformation attributes. Can be multi-sampled to support animation. |
For more information on instancing attribute conventions, please visit Katana Developer Documentation: Instancing.
Array Instancing to a point cloud
Instance Arrays have the benefit of only using one location to hold the instances, which keeps the scene graph small even in scenes with thousands of instance locations. Instance arrays read the geometry.instanceSource attribute containing the locations of the instance sources to generate the instance array. Multiple instance sources can be referenced by using the geometry.indexArray attribute containing an array of indexes of the instance sources, one for each instance. The following are steps to generate an instance array to instance geometry to the points in a point cloud.
1. Import a point cloud and instance source(s) using Alembic_In, then set the type attribute of the instance source group location to “instance source”.
2. Create an OpScript node and set its location parameter to a scene graph location where the instance array will be generated, for example: “/root/world/geo/instances”
3. In the OpScript node, create a user.pointcloud parameter and set it to the point cloud’s scene graph location path, then create a user.instanceSourceLocations string array parameter and set it to the location paths of the instance source locations. For steps on creating user parameters, see the Katana User Guide: Adding User Parameters.
4. The following OpScript Lua code, borrowed from a Pixar example found at Renderman Docs: Instancing, creates an instance array based on a point cloud and instance source locations.
Copy this code into the OpScript node's script parameter to generate the instance array with instances placed at each point of the point cloud.
-- Read the op arguments
local instanceSourceLocations = Interface.GetOpArg("user.instanceSourceLocations")
local pointCloudLocation = Interface.GetOpArg("user.pointCloudLocation"):getValue()
-- Read the point cloud's points
local points = Interface.GetAttr("geometry.point.P", pointCloudLocation):getNearestSample(Interface.GetCurrentTime())
-- Create a single location which will generate an array of instances
-- Set type for this location to 'instance array'
Interface.SetAttr('type', StringAttribute('instance array'))
-- This instance array location must point to the master locations
-- through the attribute 'geometry.instanceSource'
Interface.SetAttr('geometry.instanceSource', instanceSourceLocations)
-- The number of instance sources will be used to alternate between them when generating the indexArray below
local instanceSourceLength = #instanceSourceLocations:getNearestSample(Interface.GetCurrentTime())
-- The indexArray attribute determines which instance source each instance location represents
local indexArray = {}
-- The xform array contains the translation for each instance location
local xform = {}
-- for each instance create an instance index then build an array with transformation
for i=0,#points/3-1 do
-- each element maps to the index of the instance source in the
-- geometry.instanceSource attribute that this instance represents
indexArray[#indexArray+1] = i%instanceSourceLength
x = points[3*i+1]
y = points[3*i+2]
z = points[3*i+3]
xform[#xform + 1] = x
xform[#xform + 1] = y
xform[#xform + 1] = z
end
-- Set the index and matrix for the instance array
Interface.SetAttr('geometry.instanceIndex', IntAttribute(indexArray, 1))
Interface.SetAttr('geometry.instanceTranslate', DoubleAttribute(xform, 1))
The above OpScript sets the instance array geometry.instanceSource attribute to the instance source locations set at the user.instanceSourceLocations user parameter. Additionally, the instance array geometry.instanceIndex attribute is set to alternate between the instance sources. Finally, the instance array geometry.instanceTranslate attribute is populated with the translation information from each point in the pointcloud.
Instance Array Workaround to Vary the Assigned Material Per Instance
Unlike other instancing techniques, instance arrays do not have a mechanism to vary the material per instance directly. However, different materials can be used for instances by using instance source locations with varying materials. A benefit of using instance arrays is that all instances are contained in one scene graph location. However, this also means that locating a specific instance is almost impossible, as the individual instances do not appear in the Viewer or the Scene Graph and are only visible in a render of the scene
Please see the Instance Array to Pointcloud section above to generate an instance array. Once the instance array has been created, the material can be varied per batches of instances by varying the materials for each instance source. Use a MaterialAssign node to change the material for an instance source, and the material assign carries to each instance location that utilizes that specific instance source. Simply create MaterialAssign nodes and assign materials to the scene graph locations selected as instance sources.
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.
- Q100518: Instancing Overview
- Q100508: Hierarchical (Instance Source) Instancing
- Q100517: Leaf-level (Instance ID) Instancing
- Renderman Documentation: RenderMan 22 Docs - Instancing in Katana
ATTACHMENTS
Attachments