HDK
|
GT is a library for geometry tesselation in Houdini. In the library, there are four primary classes
GT_DataArray
GT_AttributeMap
GT_AttributeList
This class takes a GT_AttributeMap
and stores a GT_DataArray
for each attribute. Attributes can be indexed either by name or by index.
Each attribute list may contain multiple segments. In this case, the list will hold multiple data arrays for each attribute.
GT_Primitive
refine()
method which will split the primitive into simpler primitives.The GT library is used several places in Houdini. Currently, it's used in viewport rendering, Alembic export, and access is also availble through a procedural in Mantra.
Most objects are stored using smart pointers (i.e. GT_AttributeListHandle
, GT_PrimitiveHandle
and GT_DataArrayHandle
). Since objects are shared, the general philosophy is to treat the objects as const and create new data to make modifications.
All data arrays in GT are implementations of an abstract data array class. The virtual interface for a data array consists of:
const char *className()
: Return a name for the class for debugging.GT_Storage getStorage()
: Return the storage type for the data in the array.GT_Size entries()
: Return the number of items in the array For example, an array of four normals would have entries()==4
and getTupleSize()==3
GT_Size getTupleSize()
: Return the number of elements per item in the array. For example, an array of four normals would have entries()==4
and getTupleSize()==3
int64 getMemoryUsage()
: Return how much memory is used by the array.GT_DataArrayHandle harden()
: Ensure data has no external references. For example, a sorted data array may store an original data array with a separate array to implement indirect referencing of the original data:getF32
, getF16Array
, import()
, fillArray
). By far, the most efficient methods to get the data out in the form you want is to call the getF32Array()
method. In this case, if the underlying array can return you a naked pointer to its data, it will, otherwise, it will extract the data into the storage buffer passed in, and return a naked pointer to that data.GT_DANumeric
provides a simple class to store arrays of numeric data. Access to the raw data is available using the data()
method. There are specializations:GT_Unsigned8Array
GT_UInt8Array
GT_Int32Array
GT_Int64Array
GT_Real16Array
GT_Real32Array
GT_Real64Array
GT_DAIndexedString
provides a simple class to store an indexed array of shared strings.GT_DAConstantValue
A constant value, repeated for all entries in the array. There are two specializations (GT_IntConstant
and GT_RealConstant
). For example, if defining a polygon mesh of all triangles, you might use GT_IntConstant(num_triangles, 3)
GT_DARange
Similar to a range object in Python.The typical way to construct a GT_AttributeList
is to first, create a GT_AttributeMap
, then construct a new list, and then populate the list with GT_DataArray
handles.
There are methods to add attributes to the list. However, since GT_AttributeList
objects can often be shared, the method addAttribute
returns a new GT_AttributeList
object instead of modifying the existing object. For simple cases, this is can be sufficient, but for optimized code, you may want to create a GT_AttributeMap
and populate (which more efficient, but requires more code).
GT_Primitive
is an abstract base class for objects which represent geometry. One key feature of a GT_Primitive
object is that there's an interface to refine the primitive into simpler primitives. For example, a GT_PrimPolygonMesh
has a refine method which breaks the mesh into individual GT_PrimPolygon
objects.
Some of the key methods in the virtual interface include:
bool refine(GT_Refine &refiner, const GT_RefineParms *parms)
: This method is intended to split a complicated primitive into simpler primitives. The simpler primitives can then be refined to even simpler primitives. For example the GT_GEODetail
primitive is a single GT primitive which represents all the geometry in a GU_Detail
, and its refine()
method will generate new GT_Primitive
objects representing the primitives in the GU_Detail
. As an example of what a refine method might looks like, consider the GT_PrimCollect
(which simply stores a list of GT_PrimitiveHandle
objects).const char *className()
: Return a descriptive name for the class for debugging.createPrimitiveTypeId()
: Each primitive class may have a unique, run-time type id associated with it. There are several pre-defined types (see GT_PrimitiveType.h), but it's possible to assign a unique integer to a custom primitive type.enlargeBounds(UT_BoundingBox boxes[], int nsegments)
: Create bounding boxes for each motion segment defined on the primitive.enlargeRenderBounds()
: Similar to enlargeBounds
but takes rendering bounds into account. For example, a point or curve mesh should consider the "width" attribute. At the current time, this method is only called by mantra and may be deprecated in the future.getPointAttributes()
, getVertexAttributes()
, getUniformAttributes()
, getDetailAttributes()
: These methods are intended to return attributes which roughly correspond to the attribute classes for Houdini attributes. For example, a polygon mesh would return its shared points for point
attributes, it's unique point attributes for vertex
attributes, any per-face attributes for uniform
etc. It's possible that NULL
pointers can be returned if there aren't attributes of a given type.Some common primitive types are
GT_PrimCurveMesh
GT_PrimNuPatch
GT_PrimPointMesh
GT_PrimPolygonMesh
GT_PrimSubdivisionMesh
GT_GEOPrimPacked
The GT_GEODetail
class is a GT_Primitive
which is used to represent an entire GU_Detail
. There are several static methods on the class which allow you to construct a GT_Primitive
given a GU_Detail
.
GT_GEODetail
keeps references to the source geometry and builds very light-weight data structures which reference the underlying geometry. So, for example, the attribute data on the GU_Detail isn't copied into buffers, instead, there's an abstract GT_DataArray
class which extracts the data from the attributes on demand.
Since GT_GEODetail
and the data array classes hold onto references to the underlying geometry, it's imperative that the geometry remain in existence while the GT geometry is live. If this isn't possible, you can call the harden()
method on the primitive which will extract all the data from the GU_Detail and create corresponding GT data structures representing the geometry.
The refine() method for GT_GEODetail
needs to process all the primitives in the geometry. If you've created a custom GU primitive, or a custom packed primitive, you may want to specialize the GT processing of your primitive.
Each GU primitive type (including packed primitives) has an associated GT_GEOPrimCollect
class (as a singleton). When the detail hits the first primitive associated with a collector, it will call the collector's beginCollecting
method. For each primitive encountered in the detail, it will call the collectors collect
method. The collect method may choose to return a GT_PrimitiveHandle
to represent the GEO_Primitive
, or it may return an empty GT_PrimitiveHandle
. After all primitives have been processed, the endCollecting
method is called. An example of this can be seen in the tetprim HDK example.
Given a GT primitive, the GT_Util::makeGEO
method can be used to create GU_Detail's from the GT primitive. This method will refine primitives until either the method can generate Houdini geometry, or until the refinement fails. The method is able to handle many different GT primitives (see GT_Util::isSimpleGEO()
).
It's possible that different GT primitives have different attribute sets. Because of this, multiple GU_Detail objects may be created to accurately represent the original GT geometry.