概括
在任何包含重复几何体的场景中,实例化都能有效减少内存占用并提升场景图的计算性能。通常,当多个副本的几何体完全相同,且仅需进行变换时,实例化效果最佳。本文介绍了一种使用“实例数组”位置进行实例化的方法,并举例说明如何使用该方法将几何体实例化为点云中的点。
有关其他可用实例化方法的概述,请阅读Katana开发人员指南中的以下部分:实例化。
您可以参考以下Katana项目文件“ instanceArray_arnold_material.katana ”作为示例项目,其中说明了以下关于点云实例化的部分。
实例数组
以下部分简要概述了数组实例化。如需更深入地了解实例化, 请参阅 RenderMan 文档:RenderMan 26 文档 - Katana中的实例化,其中演示了如何设置所有三种实例化方法,作为实例化的入门介绍。
在实例数组中,实例位置通过类型为“实例数组”的单个位置上的属性映射到一个或多个实例源。实例数组类似于层级实例化,其优势在于可以轻松设置多个实例源。缺点是每个实例的材质不能不同。
实例数组位置必须包含geometry.instanceSource和至少一个变换属性。如果instanceSource仅包含单个路径,则geometry.instanceIndex是可选的,在这种情况下,该实例源将用于实例数组中的所有实例。
geometry.instanceSource |
包含一个或多个实例源的场景图位置路径的字符串或字符串数组属性 |
geometry.instanceIndex |
数组属性,其元素数量与所需实例数量相同。此数组中存储的值指示所需实例源在geometry.instanceSource数组中的索引。换句话说, instanceIndex构成了一个从实例索引到实例源索引的映射。 |
geometry.instanceMatrix geometry.instanceTranslate geometry.instanceRotateX geometry.instanceRotateY |
这些属性都是一个扁平数组,其中包含每个实例的变换信息。每个属性的含义与传统变换属性相同,并且可以进行多重采样以支持动画。 注意: RenderMan 仅支持使用 geometry.instanceMatrix 属性。 |
有关实例化属性约定的更多信息,请访问Katana开发人员指南:实例化。
将数组实例化为点云
实例数组的优势在于它仅使用一个位置来存储实例,即使在包含数千个实例位置的场景中,也能保持场景图的简洁。实例数组读取包含实例源位置的`geometry.instanceSource`属性来生成实例数组。可以使用包含实例源索引数组的`geometry.indexArray`属性来引用多个实例源,每个实例对应一个索引。以下步骤演示了如何生成实例数组,将几何体实例化到点云中的点上。
1. 使用 AttributeSet 节点创建或导入点云对象,并将其位置的type属性设置为pointcloud 。点云可以是任何具有geometry.point.P属性的几何体,例如来自 PrimitiveCreate 节点的几何体。
然后您将在场景图中看到点云的位置类型已更改:
2. 然后创建或导入要用作实例源的几何体。接着使用另一个 AttributeSet 节点将其父位置的类型属性设置为实例源。
例如,如果几何体位于/root/world/geo/src/teapot,则/root/world/geo/src应为实例源位置。之后,您可以在此位置下添加更多对象,以使用多个实例源。
然后您将在场景图中看到实例源的位置类型发生了变化:
3. 将这两个网络合并在一起,得到类似这样的结果:
4. 在合并操作的下游,创建一个 OpScript 节点,并将其applyWhere参数更改为指定位置。现在,您将在 OpScript 节点的参数列表中看到一个新的location参数。location参数的值将决定实例数组在场景图中的生成位置。在本例中,我们使用/root/world/geo/instances。
5. 在 OpScript 节点中,创建一个名为 user.pointCloudLocation 的字符串参数,并将其设置为点云的场景图位置路径。然后,创建一个名为user.instanceSourceLocations 的字符串数组参数,其控件类型为“场景图位置” ,并将实例源场景图位置路径作为值添加到该数组中。
有关创建用户参数和更改其小部件类型的步骤,请参阅Katana用户指南:添加用户参数。
6. 以下 OpScript Lua 代码是从Renderman Docs: Instancing中找到的 Pixar 示例精简而来,它基于点云和实例源位置创建一个实例数组。
将此代码复制到 OpScript 节点的脚本参数中,以生成实例数组,其中实例放置在点云的每个点上。
-- Read the op arguments
local instanceSourceLocations = Interface.GetOpArg("user.instanceSourceLocations")
local pointCloudLocation = Interface.GetOpArg("user.pointCloudLocation"):getValue()
-- Read the point cloud's points
local pointAttr = Interface.GetAttr("geometry.point.P", pointCloudLocation)
local points = pointAttr :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 instance source locations
-- through the attribute 'geometry.instanceSource'
Interface.SetAttr( 'geometry.instanceSource' , instanceSourceLocations)
-- The indexArray attribute determines which instance source each instance location represents
local indexArray = {}
-- for each instance create an instance index
for i= 0 ,#points/ 3-1 do
-- For this example, the instances are arbitrarily assigned to an
-- instance source
-- a more stable apporach would be to use an arbitrary attribute
-- on the point cloud to assign an instance source
indexArray[#indexArray +1 ] = i%instanceSourceLocations:getNumberOfTuples()
end
-- Set index for instance array element
Interface.SetAttr( 'geometry.instanceIndex' , IntAttribute(indexArray, 1 ))
-- geometry.instanceMatrix
-- Get the transforms from the points
local numTimeSamples = pointAttr:getNumberOfTimeSamples()
local matrixArrayMap = {}
-- to get motion blur on the instances, create an instanceMatrix at each
-- time sample available from the point cloud points attribute
for idx=0,numTimeSamples -1 do
local sampleTime = pointAttr:getSampleTime(idx)
local points = pointAttr:getNearestSample(sampleTime)
-- each instance in array has its own matrix
local matrixArray = {}
local workMatrix = Imath.M44d():toTable()
-- for each instance build a matrix with a mocked up transformation
for i=0,#points/ 3-1 do
-- grab the points that represent this instance
x = points[ 3 *i +1 ]
y = points[ 3 *i +2 ]
z = points[ 3 *i +3 ]
-- set the translate of the matrix to the points in the point cloud
workMatrix[ 13 ] = x
workMatrix[ 14 ] = y
workMatrix[ 15 ] = z
for j = 1 , 16 do
matrixArray[#matrixArray +1 ]=workMatrix[j]
end
end
matrixArrayMap[sampleTime] = matrixArray
end
Interface.SetAttr('geometry.instanceMatrix', DoubleAttribute (matrixArrayMap, #matrixArrayMap))
上述 OpScript 将实例数组geometry.instanceSource属性设置为用户参数user.instanceSourceLocations中设置的实例源位置。此外,实例数组geometry.instanceIndex属性设置为在不同的实例源之间交替。最后,实例数组geometry.instanceMatrix属性填充点云中每个点的平移信息。
7. 现在实例已经创建完成,不再需要点云,我们可以使用 Prune 节点将其从场景中移除。
现在你可以渲染以查看你的实例数组:
您可以点击此处下载完整场景: instanceArray.katana
实例数组变通方法,实现每个实例分配不同的材质
与其他实例化技术不同,实例数组没有直接为每个实例更改材质的机制。但是,可以通过使用具有不同材质的实例源位置,为实例使用不同的材质。使用实例数组的一个优点是所有实例都包含在同一个场景图位置中。然而,这也意味着几乎不可能定位到特定的实例,因为各个实例不会显示在查看器或场景图中,而仅在场景渲染中可见。
请参阅上文“实例数组到点云”部分,了解如何生成实例数组。创建实例数组后,可以通过更改每个实例源的材质,对不同批次的实例进行材质更改。使用 MaterialAssign 节点更改实例源的材质,材质分配会应用到使用该实例源的每个实例位置。只需创建 MaterialAssign 节点,并将材质分配给场景图中选定的实例源位置即可。
延伸阅读
有关实例化的概述,请参阅下方第一个资源链接。下方的其他资源将深入探讨每种实例化方法的其他高级实例化主题。
- Katana开发者指南:实例化
- Q100508:利用分层(实例源)实例化提高场景图烹饪性能
- Q100517:通过叶级(实例 ID)实例化提高场景图烹饪性能
- RenderMan 文档:RenderMan 26 文档 - Katana中的实例化
附件
我们很遗憾听到
请告诉我们