Q100517:通过叶级(实例 ID)实例化提高场景图烘焙性能

关注

概括

在任何具有重复几何体的场景中,可以使用实例化来减少内存占用并提高场景图烘焙性能。通常,当许多副本中的几何图形相同并且唯一需要的修改是变换时,实例化效果很好。本文介绍了一种使用实例 ID 属性进行实例化的方法,称为“叶级实例化”,并举例说明了如何使用它来将几何体实例化为点云的点。

有关其他可用实例化方法的概述,请阅读Katana开发人员指南中的以下部分:实例化

请参阅 Katana 项目文件“ PointcloudInstancingAndMaterialAssign_Arnold.katana ”,获取示例项目,说明以下有关点云实例的部分。

叶级实例化

以下部分是叶级实例化的简要概述。要对实例进行更深入的讨论, 请参阅 Renderman 文档:RenderMan 25 Docs - Katana中的实例化,作为实例介绍,演示了如何设置所有三种实例化方法。

在叶级实例化中,可以实例化预先存在的重复几何体,这意味着场景中已多次存在的几何体将仅加载一次,并且任何其他出现的几何体将引用内存中同一组几何体数据。通过将instance.ID属性添加到场景图中的重复几何体位置,可以轻松修改具有重复几何体的现有Katana项目,这些重复几何体将从实例中受益。然而,一个缺点是只能实例化没有子项的位置。

为了实现这一点,所有相同的位置都应该有一个匹配的instance.ID属性。渲染器选择一个位置作为实例源,然后所有其他位置都被视为该位置的实例。

注意:了解如何选择几何体作为实例源对于确定是否所有位置都需要包含几何体或者是否只有场景图中的最高位置需要几何体至关重要。请参阅渲染器文档以了解如何选择实例源。

叶级实例化到点云

使用实例 ID 实例化到点云需要 OpScript 将实例源复制到点云的每个点。一个更简单的解决方案是使用分层实例,而不需要 OpScript(请参阅Q100508:分层(实例源)实例)。然而,对任一实例化方法使用 OpScript 的好处是各个实例位置在查看器中可见,并且可以将材质单独分配给每个实例。一个潜在的缺点是场景图稍微笨重,尤其是在有数千个实例的情况下。

OpScript 生成实例位置并复制点云中每个点的instance.ID属性。 OpScript 生成位置后,渲染器会选择一个位置作为几何源,然后所有其他位置都将被视为该位置的实例。以下是实现点云叶级实例化的步骤。

1. 使用 Alembic_In 导入点云和实例源。然后将名为instance.ID的属性设置为点云位置上的任意字符串值。在此示例中, instance.ID为“bob”。

2. 创建一个 OpScript 节点并将其位置参数设置为将在其下生成实例的场景图位置,例如:“/root/world/geo/衍生资产”

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/categories 位置下找到实例位置。

然后,可以使用 MaterialAssign 节点或通过在实例位置上设置指向材质位置的materialAssign属性,将材质分配到所需位置。

延伸阅读
有关实例概述,请参阅下面的第一个资源链接。下面的其他资源深入探讨了每种实例方法的其他高级实例主题。

附件

我们很遗憾听到

请告诉我们