What & How & Why

这是本文档旧的修订版!


Primitives

Ver.17.5
Houdini 关于 Primitives 的相关知识点

什么是Primitives

Houdini 中,Primitive 代表了几何体的单位。Houdini 中可以表示为 Primitive 的单位有:

  • Polygon face
  • Packed primitives, Packed Disk primitives, and Packed Disk Sequence primitives
  • Polygon soup
  • Volume
  • Tetrahedron(四面体)
  • Bezier/NURBS 表面
  • Polygon/ Bezier/ NURBS 曲线
  • Metaballs

除此之外还有一些可以用 Primitive 来表示的几何体。这些集合体相比起 Polygon 更有性能上的优势。

Polygons and meshes

Polygon 是由一系列的边(Edge)组成的,而这些边则由一系列的顶点(Vertex) 组成。

Mesh 是一系列有序的 Polygons 组成的。相比 PolygonsMesh 有好几个特点:

  • 效率高于同等的 Polygons
  • 可以直接转换为 NURBS

上面的两种几何表述方法有几个重要的属性:

  • Open / Closed:ClosedPolygons 中的第一个顶点和最后一个顶点是共享的,并在 Houdini 内部被标记为 closed
  • Planar / non-planar:Polygons 分为 2D 和 3D。
  • Convex / concave:Polygons 根据水平垂直坐标相交的情况区分为

Packed primitives

Overview

Packed Primitives 是一种在渲染时生成几何体的技术。该技术主要的目的是通过减少几何体副本的数量和只装载必要信息,来减少 Houdini 的内存使用量。

Packed Primitives 内嵌几何体的信息。该信息可以是存储于内存中的几何体的“实体”,也可以是某个几何体的引用,或者是某个几何体在硬盘中存储的位置(路径)。

MantraHoudini ViewportSolver 等等都能解读该信息,并且能高效的显示 / 渲染 / 利用这些信息。需要注意的是,Packed Primitives 不能被编辑,因为他们只是引用。如果需要修改 Packed Geometry,需要使用 Unpack 节点取出需要编辑的几何体,编辑之后使用 Pack 节点对其重新打包。

Packed Primitives 在渲染 / 模拟大量几何体时非常有用。在 DOP 中,如果几何体至始至终不会发生形变,那么我们可以考虑将几何体封装起来。

Packed Primitives 的种类

In-memory packed primitives

当我们使用 Pack 节点将几何体转换为 Packed Primitives 之后,我们获得了 In-memory packed primitives,并且嵌入一个映射到当前版本源几何体的引用(该 Packed Primitives 是不可编辑的)。

  • 我们创建的所谓的 “嵌入引用的几何体” 实际上只是某块内存区域的引用。复制 Packed Primitives 实际上是一个对引用的拷贝过程。因此,所有的 Packed Primitives 实际上在分享着同一个源几何体;这也是为什么 Packed Primitives 如此高效的原因。
  • Packed Primitives 使用更少的内存,更容易进行 tramsform,在渲染和 viewport 中会更高效的显示。
  • 因为被引用的源几何体存在于“传统网络”中,因此我们可以很容易的进行程序化建模来生成几何体(比如使用 stamping 生成各种不同的 Packed Primitives )。总的来说,相较于传统的使用独立拷贝的方式,使用 In-memory packed primitives 会更加有交互性、更加用户友好。
  • 使用 unpack 节点将创建 In-memory packed primitives实体拷贝。 该方式允许我们在必要的时候使用传统的工作流程来处理 Packed Primitives
  • Packed 不是压缩,只是一个指向源几何体的引用。因此,单个的 Packed Primitives 相对于单个的实体几何体来说,并不能更加高效。 Packed Primitives 的优势在我们需要处理大量的拷贝个体的时候会变得更加明显。

    因此,我们有必要在进行 copy-stamping 的同时对几何体进行打包(packing)。当然,如果每个几何体都是独一无二的,那么我们是不可能从 Packed Primitives 中得到任何好处的;而且由于 Packed Primitives 有自身的 overhead,因此相较使用源几何体,我们可能需要消耗更多的内存。
Packed disk primitives

packed disk primitive 是指嵌入了指向存储在硬盘中文件的引用的 Packed Primitives 。在浏览 / 渲染的时候,Mantra / viewport 会从硬盘中读取该文件(而不是从内存中读取)。Houdini 内置的文件类型 .bgeoAlembic,都是非常高效的,适合随机读取的文件类型。

我们可以使用 File 节点来进行 Packed Disk Primitives 的创建。与 in-memory packed primitive 相同,packed disk primitive 也是单个的、不可修改的 primitive。

  • 因为 packed disk primitive 生成来源是已经生成的文件,因此唯一编辑 packed disk primitive 的方式是使用 unpack,也就是从文件创建一个源几何体的拷贝,并复制到内存中。
  • viewport 不会为每个实例创建拷贝;而是通过多次在不同的位置重复绘制同一个数据点来达到显示实例的效果。因此,viewport 可以通过各种形式来描绘被引用的实例几何体,比如 point cloud / bounding box:
  • 相较于 Houdini 必须将内存中存在的几何体整个写入 IFD 中供渲染使用,packed disk primitive 只需写入实例的引用到文件里即可。这是 packed disk primitive 可以更快的生成非常复杂的场景,并节省大量的空间。
  • 总的说来,packed disk primitive 适用于场景的的组合,特别是静态的背景。当然,因为其非常小的内存消耗,packed disk primitive 也同样适用于输出占用空间巨大的对象,比如模拟的输出。

Packed Disk Sequence primitives

Packed Disk Sequence primitivesPacked Disk primitives 类似。但对于 Packed Disk Sequence primitives,其引用的是一系列几何体的文件名和该序列的目录(index)。当 Mantra 读取 Packed Disk Sequence primitives 作为场景的一部分时,Mantra 会知道读取的是整个几何体序列(而不是当前帧的一个几何体)。因此,Mantra 可以在帧之间进行插值(interpolate)供运动模糊使用。因此,Packed Disk Sequence primitives 是一种对快速装载已绑定动画的几何体的解决方案,并且可以很好的支持运动模糊。

我们可以使用 File SOP 节点将文件按 Packed Disk Sequence primitives 的方式导入。

从技术上来讲,当我们装载 Packed Disk Sequence primitives 的时候,属于目标几何体序列的帧数 $F 已经被插值了。(这个插值处于帧范围之间)。

序列的目录(Sequence index)属性指定使用哪一帧(浮点帧)。初始值是 $FF -1$。我们可以使用 Packed Disk Edit 节点对其进行编辑。

默认情况下,当渲染长度超过 Packed Disk Sequence primitives 的序列长度时,该序列会自动循环至开始。该设定可以通过修改 primitive 属性 wrap 来进行控制(string 类型属性)。该属性有四种选项如下:

  • cycle,默认属性,自动将序列索引调整到有效的范围内(也就是自动循环)。
  • clamp,将超出索引范围外的帧限制到索引内(比如序列的范围为1-5,那么大于第5帧的渲染结果将持续使用序列 5 的结果。)
  • mirror,超出的渲染帧数会在范围内来回移动(类似乒乓在范围内持续弹跳)
  • strict,超出的渲染帧会得到空的几何体的渲染结果。
Packed fragments

如果 Packed Primitives 中包含 name 属性,那么每一个具有(分享)该 name 属性的几何体都被称为一个 Packed fragment Primitives,且所有的 Packed fragment Primitives 均包含指向源几何体的引用。也就是说,所有的 fragment 分享同一个几何体,但引用其子集(比如源几何体是一堵墙,那么 fragment 就引用的砖块,所有的砖块都来自同一堵墙。)

  • Packed fragment Primitives 适用于完整的模型,但拥有很多独立的部件(比如破碎),且特别适用于这些部件都需要有独立运动的情况。
  • 如果对 fragment 使用 unpack ,那么只有那一部分的模型会被复制到内存中(very nice!8-)
  • 需要注意的是,如果删除了较多的 fragments, 那么使用 Packed fragment Primitives 将比使用源几何体更加低效。这是因为 Houdini 会一直为所有 fragments 保留整个父、源几何体的备份(即便是 fragements 只剩一点点)。因此这种情况下,相较于直接使用源几何体,Houdini 会消耗更多的内存。
    解决方案是:在 fragments 不多的情况下使用 unpacking 将剩余的 fragments 转化为实体对象使用。

How to

  • 转换一般几何体到 Packed 几何体:Pack
  • 分离 Packed 几何体中的子物体:Unpack
  • 将几何体按照 Packed 几何体导入 DOP :DOP Import
  • 在 VEX shader 环境中访问 Packed 几何体中的属性(比如 Cd):renderstate(packed:Cd, PackedCd)

我们只能以 material attribute 的方式在 GEO 层级使用 primitive attribute。 除了 material attribute(Houdini 按照特殊情况处理),primitive 层级的属性是不能在一般的场景中工作的,因为 Houdini 将 Packed 几何体视作单个 primitive 加上一个点。

Rendering

Packed Primitives 在渲染中是非常有用的。Packed Primitives 允许我们生成 IFD,并且渲染更快,内存 / 硬盘空间使用更少。

对于标准的几何体,我们可以在两个层级下应用材质:

  • 在对象层级(Object Level)下
  • 在几何层级(SOP Level)下,使用 Martial 节点(该应用覆盖对象层级的材质)

Polygon soup

Polygon soup 也是 Polygon 的一种。这种几何数据结构特点在于:

  • 在内存中的存储非常高效和紧凑,但与此同时,它要求其所有的 Primitives 必须有同样的 Primitives 属性。
  • 在拓扑结构不改变(不添加顶点之类的)的情况下,节点可以共通编辑 Polygon soup(类似于 pass by ref);相比之下,对普通 Polygon 的处理则是每一个节点对应一个副本(类似于pass by value)。

由于 Polygon soup 独特的结构,它的建模和渲染速度会更快,而使用的内存会更少

不过 Polygon soup 对于面数较小的几何体并不是一个比较好的选项:因为 Polygon soup 有较大的管理开销,如果面数较小,处理速度反而会普通的 Polygon 慢一些。

一些需要注意的事情:

  • 将 Alembic 加载为 Polygon soup 会大大提高加载时间。
  • Polygon soup 要求拓扑的一致性,因此一些对 PrimitivesVertex 进行操作的节点和可能会改变 Polygon soup 原本描述的意思。
  • Polygon soup 中的顶点小于面数,因为它将很多位置相同的顶点合并在了一起。这要导致一些依赖于顶点的节点不能使用,比如 UV projects 就不能正确的计算出贴图的坐标。
  • 凡是需要改变几何体拓扑结构的操作,都不能对 Polygon soup 使用:比如 Poly ExtrudePoly Split 等等。
  • 使用 Polygon soup 的时候,我们可以现将其转换成普通的 Polygon soup 处理,处理完以后载将其转换回来。


具体对比的细节可以参考 When to use polygon soups, packed primitives, or regular polygons?

MetaBall

Metaball 实质上是一个隐式曲面(Implicit Surface),其一大特点是可以平滑的合并两个曲面。这使得 Metaball 在制作血液或者外表和怪异的几何体上有明显的优势。

NURBS and Bezier splines

注:有关的详细信息请查询WIKI Pedia。

NURBS,全名 Non-Uniform Rational B-Spline,是一种用控制顶点Control Vertices)定义的光滑曲线。 NURBS 所描述的曲线总是光滑的,连续的,无论描述其的顶点处于任何位置。因此 使用 NURBS 维护曲面有一个很明显的优势:你可以随意的拖动曲线中的顶点,而这些操作并不会导致几何体的纠缠(比如面相交)或者几何体的不连续(比如破面)。







Bezier 曲线相对与 NURBS 更加简单,而且允许定义的曲线在顶点处不连续,使用起来更加方便。

Parameterization

上节说过 NURBS 是由控制顶点形成的一种曲面;而控制顶点如何形成不一样的曲面呢?这一点是通过一个向量 Knots 来实现的。

待完善

顺序和角度

待完善

Quadratic primitive shapes

Houdini 支持 Primitive Spheres / Ellipsoids, Circles / Ellipses, 和 Tubes / Cone。这些几何体都被一个点定义:他们的中心点。这些几何体都支持移动,旋转,和缩放。
这些几何体都非常轻便,可以在如下的应用中使用:

  • Copy Instance
  • 粒子的容器

需要注意的是,Quadratic primitive shapes 并不具有拓扑结构,因此一些基于拓扑结构的操作节点是不会起作用的。

参考文章