All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Custom Viewport Rendering


Houdini offers several rendering hooks that allow you to augment or replace rendering in the Houdini viewport. There are two main types of hooks - primitive hooks, and scene hooks.

Primitive hooks execute rendering code based on specific primitives found within a displayed GU_Detail. They can be used to implement viewport rendering code for custom-designed primitives, add decorations and guides to existing primitives, or replace the Houdini rendering of a native primitive.

Scene hooks are not tied to any given geometry, and instead operate at the viewport level. They can do things such as render additional material to the beauty pass, draw in the overlay plane, or do a framebuffer effect such as a depth of field.

Primitive Render Hooks

A primitive render hook is responsible for creating a GR_Primitive-based object for a certain primitive type (or types) in a GU_Detail. A primitive render hook is represented by GUI_PrimitiveHook. This class is only ever instantiated once.

GUI_PrimitiveHook's main function is to inspect GT or GEO primitives passed to it and decide whether to create a custom GR_Primitive for this primitive, or pass it along to other hooks or the native Houdini rendering method. A GUI_PrimitiveHook can:

  • create a single GR_Primitive object for a single GEO or GT primitive
  • create a single GR_Primitive object for multiple GEO or GT primitives
  • create a GR_Primitive for a GEO or GT primitive, but allow processing to continue for that primitive. This allows it to augment the rendering of that primitive by drawing guides, text, or decorations, without having to draw that primitive by itself.
  • be installed for multiple times for different GT or GEO primitive types, so that families of primitives can be rendered by the same GR_Primitive code.

Installing a Primitive Render Hook

A GUI_PrimitiveHook must be registered before it can be used. This is done in one of two ways, depending on whether it is being installed on a native or custom primitive.

A hook for a native primitive can be installed via the newRenderHook() function. The type ID for a native GT or GEO primitive is known from the header (GA_PrimitiveTypes.h or GT_PrimitiveTypes.h), so it can be installed directly:

const int prim_hook_priority = 0;
table->registerGEOHook( new GR_PrimAwesomeHook,
prim_hook_priority );

A custom primitive's type ID is not known until it is registered, however, so any render hooks for this primitive must be registered when the GEO primitive is registered:

GA_PrimitiveDefinition *GU_PrimTetra::theDef = NULL;
GU_PrimAwesome::registerMyself(GA_PrimitiveFactory *factory)
// register GU primitive
theDef = factory->registerDefinition("HDK_Awesome",
// register GR primitive
const int hook_priority = 0;
DM_RenderTable::getTable()->registerGEOHook(new GR_PrimAwesomeHook,

A GUI_PrimitiveHook must have a name for message reporting, and also a render mask which describes the renderers it supports. A render hook can support all GL renderers, a subset, or a single GL renderer. These are set using the bitfield GUI_RenderMask.

GUI_PrimitiveHook(const char *hook_name,

When installing GUI_PrimitiveHook, a priority and an optional GUI_PrimitiveHookFlags parameter can be specified. The priority defines the order that hooks defined for the same primitive type will see the primitive, with precedence given to larger numbers. Any signed integer except MIN_INT32 can be used as a priority value. The priority allows multiple primitive hooks to analyze a primitive, which is useful in cases where a hook may look for the existence of an attribute to render the primitive differently (eg. 'guide_hair' is 1).

The GUI_PrimitiveHookFlags parameter is a bitfield of flags, for which there is currently one bit, GUI_HOOK_FLAG_COLLECT_PRIMS. By default, a GR_Primitive will be created for each GEO or GT primitive encountered. When the bit GUI_HOOK_FLAG_COLLECT_PRIMS is present, more than one primitive to be collected into a single GR_Primitive, either absolutely or selectively.

GUI_HOOK_FLAG_COLLECT_PRIMS is deprecated in 16.5 and will be removed in the version after that. Use GT Primitive collection instead (see GT_PrimTetra example toolkit/samples/tetprim and GT_GEOPackedSphere in toolkit/samples/packedsphere).

Installing a Scene Render Hook

Scene render hooks replace or augment render passes, and are not tied to any specific geometry. They allow you to render text in the viewport, apply effects to the beauty pass, draw your own background, or entirely replace the Houdini viewport.

To install a scene hook, derive a class from DM_SceneHook and DM_SceneRenderHook, then install it to a render pass.

const int hook_priority = 0; // normal priority
table->registerSceneHook( new GR_TextOverlayHook("text_overlay",

The render passes are, in order of rendering:

  • DM_HOOK_BACKGROUND: The first element drawn to the viewport, without any camera transform applied (matrices set up to 1:1 pixel correspondence).
  • DM_HOOK_PRE_RENDER: Elements drawn before the beauty pass, with a camera transform. The background image is drawn in the Houdini native pre-render pass.
  • DM_HOOK_BEAUTY: All opaque user-generated geometry is drawn in this pass.
  • DM_HOOK_BEAUTY_TRANSPARENT: Any transparent user-generated geometry is drawn in this pass, after the opaque beauty pass.
  • DM_HOOK_UNLIT: Unlit (non-lit, non-shadowed) geometry is drawn in this pass. Guide and template geometries are a good example of what is drawn in this pass.
  • DM_HOOK_XRAY: Objects with the X-ray flag set (such as bones) are drawn in this pass. Objects should only draw as wireframe in this pass.
  • DM_HOOK_POST_RENDER: Elements drawn after all the scene geometry, but still with the camera transform, are drawn. The origin, field guide and safe area are drawn in the native Houdini post-render pass.
  • DM_HOOK_FOREGROUND: The last elements drawn in the viewport. No native Houdini elements are drawn in this pass.

A scene hook can be registered multiple times to different render passes. This can be used to bracket the native rendering, or use data from earlier passes later on. The hook is responsible for any sharing of the render hook between passes.

The pre-render to post-render passes are rendered per-stereo eye perspective, while the background and foreground passes are only rendered once. Not all passes are available in the UV viewport (no BEAUTY_TRANSPARENT, UNLIT or XRAY).

For the BEAUTY, BEAUTY_TRANSPARENT, UNLIT and XRAY passes, a list of the geometry that falls into these categories can be queried from DM_VPortAgent, which is passed to the render method. These are getOpaqueObject() (and getNumOpaqueObjects()) for the beauty pass, getTransparentObject() for the beauty transparent pass, getUnlitObject() for the unlit pass, and getXRayObject() for the xray pass. All except the xray object list are mutually exclusive.

There is a also a DM_HOOK_FULL_SCENE hook which allows all of the above to be replaced by a single hook.

For High Quality Lighting, two additional hooks are provided, with the light provided:

  • DM_HOOK_SHADOW: Shadow pass for generating a shadow map, or other lighting technique, for the light pass. Only computed when the light or user geometry changes. Only done when shadows are enabled.
  • DM_HOOK_HQ_LIGHT_PASS: Per-light lighting pass. Additive blending is enabled when this hook is called, so only the lighting contribution for this light needs to be drawn.

The RE_Light object is passed to both passes, and data can be stored on the RE_Light by using the attachUserData(), detachUserData(), and getAttachedUserData() methods (each of which takes an index, so that multiple data chunks can be attached by the same or different viewports). The @ RE_ShadowMap object for a light can also be accessed and rendered to or used in the lighting passes.

There are several scene hook examples:

  • HDK_Sample::DM_BackgroundHook : Replaces the Houdini background with a checkered one. A good beginner example. (DM_BackgroundHook.C)
  • HDK_Sample::DM_InfoHook: Prints the current SOP at the bottom of the viewport, demonstrating how to query details in the viewport and draw text. (DM_InfoHook.C)
  • HDK_Sample::DM_SceneBoundsHook: Draws a bounding box around all objects in the scene. This demonstrates how to iterate over all displayed items in the viewprot and draw in 3D. It also shows how to restrict the hook from the UV viewport. (HDK_SceneBoundsHook.C)
  • HDK_Sample::DM_LightBloomHook: Draws a simple glow around bright objects, illustrating how to query the beauty framebuffer and use it to add an additional effect. (DM_LightBloomHook.C)
  • HDK_Sample::DM_ObjectPathHook: Draws a path with the up vectors at each frame for the current object, if animated. Demonstrates how to query objects directly and draw more complex guides in the 3D viewport. (DM_ObjectPathHook.C)
  • HDK_Sample::DM_OverdrawHook: A sample showing how to register a hook in multiple passes, sharing data between passes. This hook measures the total samples drawn in the viewport and determines the overdraw percentage, based on how many samples were rejected by depth testing. (DM_OverdrawHook.C)

Generating a GR_Primitive with a Hook

A GUI_PrimitiveHook's only reponsibility is to create a GR_Primitive from given criteria using the createPrimitive() method, or to produce a new GT_Primitive from filterPrimitive(). This method is only called if the primitive's type ID matches the one currently be processed in the GU_Detail. A hook can be a GR_Primitive creator, or a GT_Primitive filter (via GUI_HOOK_FLAG_PRIM_FILTER), but never both. This section deals with hooks that override createPrimitive() to create new GR_Primitive types.

The hook can simply handle all primitives passed to it, which are guarenteed to be of the type it was registered with, or do a more detailed inspection of the primitive's attributes or values.

virtual GR_Primitive *createPrimitive(const GT_PrimitiveHandle &gt_prim,
const GEO_Primitive *geo_prim,
const GR_RenderInfo *info,
const char *cache_name,
GR_PrimAcceptResult &processed);

Both a GT and GEO primitive are passed, though the GEO primitive will be NULL if this hook is defined for a GT primitive type. The 'info' and 'cache_name' parameters are needed by the base GR_Primitive class constructor, so they are generally passed straight though the custom GR_Primitive's constructor. The processed parameter must not be GR_NOT_PROCESSED if a new GR_Primitive is returned, and it can take the following values:

  • GR_PROCESSED: A GR_Primitive has been created, do not process further hooks or native Houdini primitives for this primitive.
  • GR_PROCESSED_NON_EXCLUSIVE: A GR_Primitive has been craeted, but continue processing hooks or Houdini primitives for this primitive.

The non-exclusive case often requires that the GUI_PrimitiveHook is installed with a higher priority than other custom hooks for the same type, especially if they return GR_PROCESSED.

Once a GR_Primitive is created, it gains some autonomy in maintaining itself. If the hook was created with the GUI_HOOK_FLAG_COLLECT_PRIMS option, subsequent primitives of the same type will first be passed to existing GR_Primitives through this virtual GR_Primitive method:

virtual GR_PrimAcceptResult acceptPrimitive(GT_PrimitiveType t,
int geo_type,
const GT_PrimitiveHandle &ph,
const GEO_Primitive *prim);

This gives GR collection primitives a chance to process the primitive before GUI_PrimitiveHook generates a new GR_Primitive. acceptPrimitive() returns one of GR_NOT_PROCESSED (not interested in this primitive), GR_PROCESSED or GR_PROCESSED_NON_EXCLUSIVE (both of which are described above). This method should not be used to build GL data structures, only to accept or add a primitive.

Collection primitives also have an additional method, resetPrimitives(), which is called before processing of a GU_Detail starts. This provides an opportunity to clear the collected primitives.

In order to provide better performance, the viewport attempts to reuse existing GR primitives whenever possible. If a GU_Detail is changed, the next update for the detail will first call acceptPrimitive() for each primitive that was previously generated. In this case, the GT or GEO type passed to acceptPrimitive() may not match the GR_Primitive's expected type.

GR_Primitives are deleted when no longer needed. This can occur if:

  • The detail is no longer being displayed
  • The primitive has been removed from the detail
  • For a GR collection primitive, all primitives that met the criteria were removed from the detail
  • Primitives were reordered in the detail such that a match between a primitive and its GR primitive could not be made.

Rendering Primitives

Once a GR_Primitive has been created for a primitive, or group of primitives, it will generally be updated and rendered. A GR_Primitive can be persistent over multiple GU_Detail changes, so information can be cached within the GR_Primitive itself or in the GL cache. There are two main phases of a GR_Primitive - updating and rendering.

A GR_Primitive is updated primarily through its update() method. It is responsible for creating all data required for the render methods. Textures, buffers, and other GL objects should all be created in this method.

virtual void update(RE_Render *r,
const GT_PrimitiveHandle &primh,
const GR_UpdateParms &p);

update() is called much less often than render, so it is recommended that any heavy computation is done in update() rather than the render methods. update() is called when:

The reason for the update is stated in the bitfield p.reason. Multiple reasons may be given.

In addition to update(), there is a virtual viewUpdate() method which is called if only the view frustum has changed and the primitive requested view change updates.

Rendering is performed in render(). The basic render method is:

virtual void render(RE_Render *r,
GR_RenderMode render_mode,
GR_DrawParms draw_parms);

Each primitive can be rendered in a variety of ways, not all of which need to be supported by a custom primitive. The render modes are:

  • GR_RENDER_BEAUTY: Normal quality beauty pass, direct lighting render.
  • GR_RENDER_MATERIAL: High Quality render, deferred shading render.
  • GR_RENDER_CONSTANT: Primitive rendered in a constant color, no shading.
  • GR_RENDER_WIREFRAME: Wireframe representation.
  • GR_RENDER_XRAY_LINE: Wireframe, but with hidden lines muted.
  • GR_RENDER_HIDDEN_LINE: Wireframe, but with hidden lines removed.
  • GR_RENDER_GHOST_LINE: Wireframe, with a dark constant fill of the surface.
  • GR_RENDER_MATERIAL_WIREFRAME: Wireframe when HQ Lighting is active.
  • GR_RENDER_DEPTH: Depth buffer render only, nonlinear [0..1] clip space
  • GR_RENDER_DEPTH_CUBE: Depth render, linear depth, for a cube map
  • GR_RENDER_DEPTH_LINEAR: Depth render, linear depth, for a regular shadow map
  • GR_RENDER_MATTE: Constant fill color, but with depth check against the beauty pass's depth
  • GR_RENDER_XRAY: Render an X-ray matte of the object
  • GR_RENDER_OBJECT_PICK: Object selection. A shader should not be set, or must output the value of 'uniform ivec4 glH_PickID'
  • GR_RENDER_POST_PASS: The primitive requested a post-pass. The post-pass ID should be checked against the ID in 'myInfo' (GR_RenderInfo) in case multiple post-passes were requested.

Modes when you don't intend to support should immediately return from render(). Ignoring some modes, like Hidden Line, will cause your geometry to disappear when a user selects "Hidden Line" mode, so in some cases it is better to substitute a close render mode (like Wireframe). Other modes, like Matte or Depth Linear, will cause the object not to highlight when located or participate in shadow maps.

There are also variations for some modes, usually shaded ones, passed in the GR_RenderFlags parameter:

  • GR_RENDER_FLAG_FLAT_SHADED: Do not interpolate normals over the surface.
  • GR_RENDER_FLAG_UNLIT: Render the surface without lighting.
  • GR_RENDER_FLAG_WIRE_OVER: Render the surface with wireframe guides overlaid (polygon outlines, isoparms)
  • GR_RENDER_FLAG_FADED: Ignore the Cd attribute (color), used for template rendering
  • GR_RENDER_FLAG_COLOR_OVERRIDE: The Cd attribute has been overridden
  • GR_RENDER_FLAG_ALPHA_OVERRIDE: The Alpha attribute has been overridden
  • GR_RENDER_FLAG_POINTS_ONLY: Render the primitive's points only.
  • GR_RENDER_FLAG_SHADED_CURVES: Render curves as shaded, lit strips
  • GR_RENDER_FLAG_WIRE_PRIMS_ONLY: Only render wireframe primitives, no solids.
  • GR_RENDER_FLAG_USE_SUBDIVISION: Use subdivision for the curve or surface, if supported.
  • GR_RENDER_FLAG_POINT_UV_POS: (UV Viewport only) - UV is a point attribute
  • GR_RENDER_FLAG_VERTEX_UV_POS: (UV Viewport onlu) - UV is a vertex attribute
  • GR_RENDER_FLAG_BONE_DEFORM: Use deformation for up to 4 bones
  • GR_RENDER_FLAG_BONE_DEFORM_SINGLE: Use deformation, only a single bone.
  • GR_RENDER_FLAG_HIDE_MATERIALS: Do not draw with any materials other than the default.

render() is frequently called more often than update(), such as when tumbling the view, so it is recommended that this method be as lightweight as possible.

There is a fairly large difference between the GL3 renderer and traditional OpenGL 1.x and 2.x in terms of the rendering environment. OpenGL 3 does not use the fixed function lighting, material and GL builtin state, such as the matrix stacks and color. The GL2.x builtin attributes are no longer supported, such as gl_Vertex, gl_Normal, gl_MultiTexCoord#, and gl_Color.

In core OpenGL 3.2, none of these builtins or fixed attributes exist. The fixed function pipeline is removed, as are many of the GLSL builtin uniforms. Instead, the vertex shader inputs are passed using generic vertex attributes, which share the same name as their Houdini counterparts (P, Cd, N, uv, etc). Lighting and material information is sent in uniform blocks, and transforms are passed using Houdini-builtin uniforms (glH_ObjectMatrix, glH_ProjectMatrix). Because of this, shaders or fixed function code designed for OpenGL 1 or 2 will not work in the GL3 viewport - objects will simply not display.

There are also several ways to do OpenGL rendering within Houdini. The first method is to use OpenGL directly. The second uses higher-level RE objects such as RE_Shader, RE_Geometry, and RE_VertexArray. These gain the benefits of the Houdini GL cache, GL extension abstractions, and simpler interfaces. The third way is through GR classes designed to render various classes of objects in the viewport (GR_PolySurfaceGL3, GR_VolumeGL3, GR_PointsGL3). These classes know all about picking, selection, instancing, and special draw modes, like hidden line, ghosting and shadowmap rendering.

All three methods have their advantages, and generally trade off flexibilty for quicker development when moving from GL to RE to GR.

The following pages cover these rendering topics in more detail.

Creating a GT_Primitive with a Filter Hook

In addition to the normal GUI_RenderHook, there is a primitive filter hook. It is registered with the GUI_HOOK_FLAG_PRIM_FILTER flag (and only that flag):

const int prim_hook_priority = 0;
table->registerGEOHook( new GR_PrimFilterHook,

When this type of hook is active, it creates a new GT_Primitive for the input GT or GEO primitive:

GT_PrimitiveHandle filterPrimitive(const GT_PrimitiveHandle &gt_prm,
const GEO_Primitive *geo_prm,
const GR_RenderInfo *info,
GR_PrimAcceptResult &processed);

The new GT primitive may be of the same type as the input primitive, or it may be a completely different type, such as converting a polygon mesh into a point cloud.

A filter hook should always set 'processed' to GR_PROCESSED if it always or might affect its primitive, such as if it is conditionally applied using display option. This ensures that the refinement process knows that it may be conditionally applied. Returning a NULL GT_PrimitiveHandle from a filter will cause it to be ignored even if GR_PROCESSED is returned.

Registering a primitive display option for a filter handle requires the 'refine_requred' flag to be set:

GR_UserOption *opt = table->installGeometryOption("visNasCd", "Visualize N");

This will trigger a geometry refine when the option is toggled so that the filterPrimitive() method is called again. Only filter hooks require this; primitive creation hooks should not set it.

The filter effect can then be toggled on or off (as taken from the GUI_PolygonNormalShade HDK sample):

GUI_PolygonNormalShade::filterPrimitive(const GT_PrimitiveHandle &gt_prm,
const GEO_Primitive *geo_prm,
const GR_RenderInfo *info,
GR_PrimAcceptResult &processed)
// we're interested in this prim, but are not doing anything with it
// at this time. Mark it as processed but don't return a new prim.
processed = GR_PROCESSED;
return ph;
// using gt_prim, create a new GT_Primitive and assign to ph //
return ph;

The only restriction for a filter hook is that it can only return a single GT_Primitive. It cannot return a collection of GT_Primitives.

See Also