# Hierarchical Subdivision Surfaces

## Hierarchical Subdivision Surfaces

November 2004

### Introduction

PhotoRealistic RenderMan 3.8 introduced subdivision surfaces to the renderer. PRMan 12.5 extends this class of geometric primitives to support the powerful concept of hierarchical editing. To understand the hierarchical aspect of subdivision, we realize that subdivision itself leads to a natural hierarchy: after the first level of subdivision, each face in a subdivision mesh subdivides to four quads (in the Catmull-Clark scheme), or four triangles (in the Loop scheme). This creates a parent and child relationship between the original face and the resulting four subdivided faces, which in turn leads to a hierarchy of subdivision as each child in turn subdivides. A hierarchical edit is an edit made to any one of the faces, edges, or vertices that arise anywhere during subdivision. Normally these subdivision components inherit values from their parents based on a set of subdivision rules that depend on the subdivision scheme. A hierarchical edit overrides these values. This allows for a compact specification of localized detail on a subdivision surface, without having to express information about the rest of the subdivision surface at the same level of detail.

### Hierarchical Path Specification

In order to perform a hierarchical edit, we need to be able to name the subdivision component we are interested in, no matter where it may occur in the subdivision hierarchy. This leads us to a hierarchical path specification for faces, since once we have a face we can navigate to an incident edge or vertex by association. We note that in a subdivision mesh, a face always has incident vertices, which are labelled (in relation to the face) with an integer index starting at zero and in consecutive order according to the usual winding rules for subdivision surfaces. Faces also have incident edges, and these are labelled according to the origin vertex of the edge.

A subdivided face is specified by a series of integers that indicate a path of traversal, starting at a base face and proceeding down the subdivision hierarchy. The first integer is the index of a base face in the mesh — it is the same number used to index into the nvertices array passed to the HierarchicalSubdivisionMesh call (described later). Subsequent integers in the path are a zero-based index to one of the children of the previous face in the path. Note that in the Catmull-Clark subdivision scheme, the first subdivision splits all non-quad faces into quads, resulting in a mesh consisting solely of quadrilateral faces. This means that the second integer (the child of the base face) can be an integer greater than 3 (depending on the number of vertices in the base face), but every integer after that must be less than 4.

To properly specify a face, we need to know how child faces are indexed with respect to their parent. In turn, this ordering depends on how the vertices of the parent face are indexed. In PRMan, the indexing of subfaces and vertices ultimately depends on whether or not the first face in the path is extraordinary (has a number of vertices not equal to four in the Catmull-Clark scheme, or not equal to three in the Loop scheme). In particular, the immediate child subfaces of an extraordinary face have different vertex ordering than the immediate child subfaces of a regular face. The following diagram illustrates the ordering. Note that subface vertices are overlaid on top of the parent vertices for simplicity, but obviously during subdivision they may not have the same position.

In this diagram, the indices of the vertices of the base face are marked in red; so on the left we have an extraordinary Catmull-Clark face with five vertices (labeled 0-4) and on the right we have a regular Catmull-Clark face with four vertices (labelled 0-3). The indices of the child faces are blue; note that in both the extraordinary and regular cases, the child faces are indexed the same way, i.e. the subface labeled n has one incident vertex that is the result of the subdivision of the parent vertex also labeled n in the parent face. Specifically, we note that the subface 1 in both the regular and extraordinary face is nearest to the vertex labelled 1 in the parent.

The indices of the vertices of the child faces are labeled green, and this is where the difference lies between the extraordinary and regular case; in the extraordinary case, vertex to vertex subdivision always results in a vertex labeled 0, while in the regular case, vertex to vertex subdivision assigns the same index to the child vertex. Again, specifically, we note that the parent vertex indexed 1 in the extraordinary case has a child vertex 0, while in the regular case the parent vertex indexed 1 actually has a child vertex that is indexed 1. Note that this indexing scheme was chosen to maintain the property that the vertex labeled 0 always has the lowest u/v parametric value on the face.

By appending a vertex index to a face specification, we can create a vertex path specification — for example, (656 4 1 2 3) specifies the 3rd vertex of the 2nd child face of the 1st child face of the 4th child face of the 656th face of the subdivision mesh. (Since the second integer is four, the 656th face of the mesh must have at least five vertices for this to be a valid path.) A diagram illustrating a situation where the vertex path (656 4 1 2 3) exists is shown below:

In this more complicated diagram showing multiple levels of hierarchy, we note that the base level face has five children indexed using the rules for an extraordinary face; the child indexed 4 has four child faces which are indexed using the rules for a regular face; the child of that face indexed 1 also has four subfaces also indexed using the rules for a regular face; and finally the child of that face indexed 2 has a vertex indexed 3, which is the vertex we're interested in.

Some other noteworthy details about this diagram: Path (656 4 1) specifies the parent vertex of (656 4 1 1). Notice that (656 4 1 2 3) has no parent vertex, since it originated by subdivision of the edge connecting vertices (656 4 1 2) and (656 4 1 3). Finally, notice that, unlike faces, vertices may be aliased with multiple path specifications — for example, (656 4 1) is an alias for (656 0 3).

### RenderMan Interface

A new RI call has been introduced to support hierarchical subdivision edits on subdivision surfaces.

```  RiHierarchicalSubdivisionMesh (RtToken scheme, RtInt nfaces, RtInt nvertices[], RtInt vertices[],
RtInt ntags, RtToken tags[], RtInt nargs[],
RtInt intargs[], RtFloat floatargs[], RtToken stringargs[],
..parameterlist...)
```

RIB Binding:

```  HierarchicalSubdivisionMesh scheme nvertices vertices tags nargs intargs floatargs stringargs
...parameterlist...
```

Like the RiSubdivisionMesh call, components of the subdivision mesh may be tagged by the user to have specific properties. Unlike the RiSubdivisionMesh call, each tag can have zero or more string arguments, as well as zero or more integer arguments and zero or more floating-point arguments. Hence, the number of arguments provided with each tag is specified by the array nargs, which has a length of ntags x 3 (unlike RiSubdivisionMesh, where the length is ntags x 2).

For each tag, nargs contains an integer specifying the number of integer operands found in the array intargs, followed by an integer specifying the number of floating-point operands found in the array floatargs, followed by an integer specifying the number of string operands found in the array stringargs. Thus, given m in [0, ntags - 1], the length of intargs is equal to the sum of all the 3m numbered elements of the array nargs; the length of floatargs is equal to the sum of all the 3m+1 numbered elements of the array nargs; and the length of stringargs is equal to the sum of all 3m+2 numbered elements of the array nargs.

Hierarchical subdivision surfaces support the same tags as standard subdivision surfaces, which are all specified in the same fashion save that the number of string arguments are set to zero. The following is an example of usage of HierarchicalSubdivisionMesh with the interpolateboundary tag, and without any hierarchical edits.

```  HierarchicalSubdivisionMesh "catmull-clark" [4 4 4 4 4 4 4 4 4]
[4 5 1 0 5 6 2 1 6 7 3 2 8 9 5 4 9 10 6 5 10 11 7 6 12 13 9 8 13 14 10 9 14 15 11 10]
["interpolateboundary"] [1 0 0] [2] [] []
"P" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]```

The full power of hierarchical subdivision surfaces is realized through the use of three new hierarchical edit tags, all of which accept and require string arguments. These tags are: "vertexedit", "edgeedit", and "faceedit".

### Vertex Edits

```  ["vertexedit"]
[<Σ(vertex path lengths)> <(amount of float data per vertex) × nvertices> <3 × noperators>]
[<vertex paths>]
[<edit values>]
[<"set"|"add"> <variable name> <"value"|"sharpness"> ... ]```

A vertex edit overrides the value or the sharpness of a set of primitive variables on the subdivision mesh, at a set of vertices anywhere in the subdivision hierarchy. It is specified using the vertexedit tag. It is easiest to interpret this tag as a set of operators specified in the string list, each applied to a set of vertices specified in the integer list, with the arguments to the operators specified in the float list.

The operators currently accepted by the vertexedit tag are described by triplets of strings. The size and interpretation of the float arguments are determined by these operators, as described below.

1. The first string can be one of the values "set" or "add". "set" indicates the primitive variable value or sharpness is to be set directly to the values specified in the floating point list. "add" adds a value to the normal result computed via standard subdivision rules. In other words, this operation allows value offsets to be applied to the mesh at any level of the hierarchy.
2. The second string is the name of a variable to edit. This variable must exist in the parameter list of the subdivision surface, and must be of storage class varying, vertex, or facevarying (since it is nonsensical to apply a vertex edit to a variable of uniform or constant storage).
3. The third string can be either "value" or "sharpness". "value" causes the value of the primitive variable to be overriden, while "sharpness" overrides the subdivision mask of the primitive variable at that vertex. If "value" is specified, the type of the variable as declared in the parameter list determines the number of floating point arguments that will be required for each vertex. For variables that are of type point, vector, normal, or matrix, it is assumed that the float data will be presented in object space. An appropriate transformation will be applied during the render. Note that in the special case of a "add" operation applied to data of type point the three floats will be subject to a vector transformation, not a simple point transformation. When "sharpness" is specified, only one floating point argument will be required.

The integer arguments will be interpreted as a series of vertex path specifications, as defined above. Each vertex path must be prefaced with a path length, with the end result being a "packed" encoding of vertices. The number of vertices being edited is implicit and computed by unpacking these integers into individual paths.

The floating point arguments supplied are values to the operators, one set per vertex, specified in a vertex interleaved fashion, with the contents of each set determined by the string operators as described above. For example, if the vertexedit tag specifies the three operators "set" "P" "sharpness", "add" "P" "value", and "set" "s" "value", for each vertex we expect a set of 5 float values in order: 1 for the sharpness edit on "P", 3 for the value edit on "P", and 1 for the value edit on "s". These five float values are expected to be packed together and specified for each vertex indicated in the vertex paths.

Unlike all other tags, vertexedit tags can be deformation motion blurred with different values. In other words, multiple HierarchicalSubdivisionMesh calls within the same MotionBegin/MotionEnd blocks can have changing vertexedit tags which will be motion blurred. Currently, this is restricted to vertex value edits on P, and only the float arguments are allowed to be different (in other words, the integer vertex paths cannot change).

The following RIB example applies a vertex value edit on four paths each of length of three. The "add" operations modifying both "P" and "__Pref" data have been selected. For clarity, the first vertex path (a path of length 3) has been highlighted in blue and data in the tags associated with the same vertex has been highlighted in red.

```  HierarchicalSubdivisionMesh "catmull-clark" [4 4 4 4 4 4 4 4 4]
[4 5 1 0 5 6 2 1 6 7 3 2 8 9 5 4 9 10 6 5 10 11 7 6 12 13 9 8 13 14 10 9 14 15 11 10]
["interpolateboundary" "vertexedit"] [1 0 0 16 24 6]
[2 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3]
[0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1] ["add" "P" "value" "add" "__Pref" "value"]
"P" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]
"vertex point __Pref" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]```

By increasing the path lengths, the vertices being edited are further down in the subdivision hierarchy, and as a result the effect is more localised:

```  HierarchicalSubdivisionMesh "catmull-clark" [4 4 4 4 4 4 4 4 4]
[4 5 1 0 5 6 2 1 6 7 3 2 8 9 5 4 9 10 6 5 10 11 7 6 12 13 9 8 13 14 10 9 14 15 11 10]
["interpolateboundary" "vertexedit"] [1 0 0 20 24 6]
[2 4 4 1 1 0 4 4 1 1 1 4 4 1 1 2 4 4 1 1 3]
[0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1] ["add" "P" "value" "add" "__Pref" "value"]
"P" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]
"vertex point __Pref" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]```

The following RIB example applies a vertex value edit on four vertices, applying a "set" operation to "s" and "t" data. In effect, this changes the local texture coordinates of the mesh.

```  Surface "texmap" "string texname" ["ratGrid.tex"]
HierarchicalSubdivisionMesh "catmull-clark" [4 4 4 4 4 4 4 4 4]
[4 5 1 0 5 6 2 1 6 7 3 2 8 9 5 4 9 10 6 5 10 11 7 6 12 13 9 8 13 14 10 9 14 15 11 10]
["interpolateboundary" "facevaryinginterpolateboundary" "vertexedit" "vertexedit"] [1 0 0 1 0 0 16 4 3 16 4 3]
[2 0 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3]
[1 1 0 0 0 1 1 0]
["set" "s" "value" "set" "t" "value"]
"P" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]
"facevarying float s" [0.33 0.33 0 0 0.33 0.33 0 0 0.33 0.33 0 0
0.66 0.66 0.33 0.33 0.66 0.66 0.33 0.33 0.66 0.66 0.33 0.33
1 1 0.66 0.66 1 1 0.66 0.66 1 1 0.66 0.66]
"facevarying float t" [0 0.33 0.33 0 0.33 0.66 0.66 0.33 0.66 1 1 0.66
0 0.33 0.33 0 0.33 0.66 0.66 0.33 0.66 1 1 0.66
0 0.33 0.33 0 0.33 0.66 0.66 0.33 0.66 1 1 0.66]```

The following RIB example applies a vertex value edit to __Pref and both a vertex value edit and a vertex sharpness edit to P, with corner strengths of 10 supplied for the latter. This time there are two separate "vertexedit" tags, with the second applying only the sharpness edit. Only the first vertex of the second tag will be highlighted.

```  HierarchicalSubdivisionMesh "catmull-clark" [4 4 4 4 4 4 4 4 4]
[4 5 1 0 5 6 2 1 6 7 3 2 8 9 5 4 9 10 6 5 10 11 7 6 12 13 9 8 13 14 10 9 14 15 11 10]
["interpolateboundary" "vertexedit" "vertexedit"]
[1 0 0 16 24 6 16 4 3]
[2 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3]
[0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 10 10 10 10]
"P" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]
"vertex point __Pref" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]```

### Edge Edits

```  ["edgeedit"]
[<Σ(edge path lengths)> <nedges> <3 × nedges>]
[<edge paths>]
[<sharpness values>]
[<"set"|"add"> <variable name> "sharpness" ... ]```

An edge edit modifies a property of any edge in the subdivision hierarchy. Currently, the only valid property that can modified is the sharpness of a primitive variable (the crease strength), which simplifies this tag since only one float argument needs to be specified per vertex in all cases. In all other respects an edge edit is specified in the same way as a vertex edit, except that the paths will be interpreted to point at the origin vertex of the edge; the destination vertex is implied to be the next vertex in order.

The following RIB example applies an edge sharpness edit to four vertices, applying a crease strength of 10 to "P" data. For clarity, the first edge path in the edgeedit tag has been highlighted in blue and its associated data highlighted in red.

```  HierarchicalSubdivisionMesh "catmull-clark" [4 4 4 4 4 4 4 4 4]
[4 5 1 0 5 6 2 1 6 7 3 2 8 9 5 4 9 10 6 5 10 11 7 6 12 13 9 8 13 14 10 9 14 15 11 10]
["interpolateboundary" "vertexedit" "edgeedit"] [1 0 0 16 24 6 16 4 3]
[2 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3]
[0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 10 10 10 10]
"P" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]
"vertex point __Pref" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]```

The following example combines vertex value, vertex sharpness, and edge sharpness edits, all operating near the same face.

```  HierarchicalSubdivisionMesh "catmull-clark" [4 4 4 4 4 4 4 4 4]
[4 5 1 0 5 6 2 1 6 7 3 2 8 9 5 4 9 10 6 5 10 11 7 6 12 13 9 8 13 14 10 9 14 15 11 10]
["interpolateboundary" "vertexedit" "edgeedit"] [1 0 0 16 28 9 16 4 3]
[2 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3]
[0 0 -1 0 0 -1 10 0 0 -1 0 0 -1 10 0 0 -1 0 0 -1 10 0 0 -1 0 0 -1 10 10 10 10 10]
["add" "P" "value" "add" "__Pref" "value" "set" "P" "sharpness" "set" "P" "sharpness"]
"P" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]
"vertex point __Pref" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]```

### Face Edits

```  ["faceedit"]
[<Σ(face path lengths)> <(amount of float data per face) × nfaces> <size of string values>]
[<face paths>]
[<edit values>]
[<"hole"> or
< <"set"|"add"> <variable name> "value" > or
< "attributes" <statename> <subset> > ...]```

A face edit is analogous to a vertex edit: it modifies a property of a group of faces each of which can be anywhere in the subdivision hierarchy. These properties include marking faces as holes, editing the values of uniform or constant primitive variables associated with those faces, and restoring a saved attribute state.

Like vertex edits, operators are described in the string argument list. Unlike the vertex edit tags, some of the arguments to the operators can themselves be strings and can be found in the same string argument list. Hence the format of the string argument list is somewhat more free form.

• The "hole" operation introduces holes (missing faces) into the subdivision mesh at any level in the subdivision hierarchy. The faces will be deleted, and none of their children will appear (you cannot "unhole" a face if any ancestor is a "hole"). This operation takes no float or string arguments.
• The "set" or "add" operators modify the value of primitive variables associated with faces. The string argument immediately following either of these must be the name of the primitive variable. This variable must exist in the parameter list of the subdivision surface, and can only be of uniform or constant storage. Like vertex value edits, variables that are of type point, vector, normal, or matrix are assumed to be in object space and will be appropriately transformed by the renderer; and in the special case of a "add" operation applied to data of type point, the three floats will be subject to a vector transformation, not a simple point transformation. Unlike vertex value edits, only one primitive variable value is supplied for the entire operator, and not one per face; this value will be copied to all faces. (This means that editing the value of the same variable on another set of faces requires a completely separate "faceedit tag.) Also, the variable is allowed to be of type "string", in which case no float data is expected, and the string value is supplied immediately following the variable name. To illustrate this operator, consider the following example:
```	[2 1 2 2 1 3 2 1 4] [0 0 1] ["set" "Ldir" "set" "txname" "grass.tx"]
```
Here, three faces (1 2), (1 3), and (1 4) have the value of (presumably a uniform vector) "Ldir" set to (0, 0, 1), and also set the value of (string) "txname" to "grass.tx". Note that only three float values are specified (one value for the Ldir vector), and the string value is specified inline with the operator description.
• The "attributes" operator modifies the attribute state bound to the face. By default, all faces in the subdivision mesh inherit the same attribute state that was in effect when the HierarchicalSubdivisionMesh was encountered. The "attributes" operator allows a group of faces to instead be bound to a attribute state that was named and saved using RiResource. The operator takes no float arguments, and two string arguments immediately following the "attributes" keyword; the first argument is the name of an saved attribute state (saved earlier using RiResource("attributes", name, "string operation", "save", "string subset", subset, RI_NULL); and the second argument is the subset of the attribute state that should be restored.

The following RIB example applies an edit to the value of the string "txname", which is used as an input parameter to the surface shader "texmap". Two faces are being affected here, even though only one value "grass.tex" is supplied.

```  Surface "texmap" "string texname" ["flowers.tex"]
HierarchicalSubdivisionMesh "catmull-clark" [4 4 4 4 4 4 4 4 4]
[4 5 1 0 5 6 2 1 6 7 3 2 8 9 5 4 9 10 6 5 10 11 7 6 12 13 9 8 13 14 10 9 14 15 11 10]
["interpolateboundary"  "faceedit" "vertexedit"] [1 0 0 6 0 3 16 24 6 ]
[2 2 4 1 2 4 3 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3]
[0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1]
"P" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]
"vertex point __Pref" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]
"constant string texname" ["flowers.tex"]```

The following RIB example applies a single hole edit.

```  HierarchicalSubdivisionMesh "catmull-clark" [4 4 4 4 4 4 4 4 4]
[4 5 1 0 5 6 2 1 6 7 3 2 8 9 5 4 9 10 6 5 10 11 7 6 12 13 9 8 13 14 10 9 14 15 11 10]
["interpolateboundary" "faceedit" "vertexedit"] [1 0 0 4 0 1 20 12 3]
[2 3 4 1 1 4 4 1 1 0 4 4 1 1 1 4 4 1 1 2 4 4 1 1 3] [0 0 -1 0 0 -1 0 0 -1 0 0 -1]
"P" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]```

The following RIB example applies an attributes edit.

```  AttributeBegin
Surface "rmarble"
Resource "rmarble" "attributes" "string operation" "save"
AttributeEnd
Surface "plastic" "roughness" [0.05]
Color [0.4 0.4 0.8]
HierarchicalSubdivisionMesh "catmull-clark" [4 4 4 4 4 4 4 4 4]
[4 5 1 0 5 6 2 1 6 7 3 2 8 9 5 4 9 10 6 5 10 11 7 6 12 13 9 8 13 14 10 9 14 15 11 10]
["interpolateboundary"  "faceedit" "vertexedit"] [1 0 0 3 0 3 16 24 6 ]
[2 2 4 1 3 4 1 0 3 4 1 1 3 4 1 2 3 4 1 3]
[0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1]
"P" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]
"vertex point __Pref" [-1 -1 0 -0.333333 -1 0 0.333333 -1 0 1 -1 0
-1 -0.333333 0 -0.333333 -0.333333 0 0.333333 -0.333333 0 1 -0.333333 0
-1 0.333333 0 -0.333333 0.333333 0 0.333333 0.333333 0 1 0.333333 0
-1 1 0 -0.333333 1 0 0.333333 1 0 1 1 0]```

### Appendix

#### Limitations

In release 12.5, vertex and edge sharpness edits can not be applied independently to primitive variables. Currently, the variable specified will be ignored (although the parser still requires it), and the sharpness will be applied to all variables on the vertex or edge. This limitation may be removed in a future release.

#### Compatibility with Maya Subdivision Surfaces

The path specification for Maya subdivision surfaces differs slightly from PRMan's specification. In particular, Maya does not differentiate between extraordinary and regular faces when ordering vertices after the first level of subdivision. The following code fragment using the Maya subdivision surface API illustrates how to compensate for this when converting a hierarchical subdivision path from Maya to PRMan.

```  MFnSubd subdFn;
MUint64 vertId;
int i, base, first, level, path, corner, offset, pathcomponent;

MFnSubdNames::fromMUint64(vertId, base, first, level, path, corner);

printf("%d %d ", base, first);
offset = 0;
if (subdFn.polygonVertexCount(MFnSubdNames::baseFaceIndexFromId(base)) == 4) {
offset = first;
}
for (i = 0; i < level - 1; i++) {
pathcomponent = path & 3;
path >>= 2;
printf("%d ", (pathcomponent + offset) % 4);
}
if (level >= 0) {
printf("%d", (corner + offset) % 4);
}```