Houdini 12 Shading

Overview

OpenGL shaders are hardware accelerated shaders that are executed on the video card. OpenGL shaders only affect the viewport – they are not rendered. You can create an OpenGL shader and include it in a material to show a better representation of the material in the viewport.

Writing an OpenGL shader

Creating a new shader type

OpenGL shaders are written using GLSL (the OpenGL Shader Language). Before you can create an OpenGL shader you need to understand GLSL and its related concepts such as vertex shaders and fragment shaders.

  1. Choose File > New operator type.

  2. Click on SHOP Type.

  3. In the Network Type menu, choose GLSL Shader.

  4. Enter an internal Name for the shader and a human-readable Label.

  5. Click Accept. The type properties window for the new shader type appears.

  6. Click the Code tab. The node starts with some default shader code. You can use this as a starting point for creating your shader.

    There are two shader targets for the viewport - GL2.1 and GL3.2. The GL2.1 shader target consists of two shaders, the vertex and fragment shader. These shaders generally use the GLSL builtin state, such as the lighting state, material state and GL matrix stacks. The GL3.2 shader target also includes an optional geometry shader, which executes between the vertex and fragment shaders on GL primitives. Both shader targets can be defined; the GL2.1 target is used for the GL2.1 and H11 viewports, while the GL3.2 target is used for the GL3.2 viewport.

    The Code tab provides a simple editor for working with GLSL code. The editor has three or four text boxes: one for the vertex shader, one for the geometry shader for the GL3.2 shader, one for the fragment shader, and one for compiler output. You can drag the dividers between the three panes to resize them.

  7. Click Test compile to try compiling the default code. The output of the compiler appears in the third pane.

See the OpenGL GLSL documentation for more information on programming in GLSL.

You cannot currently create a GLSL shader using VOPs.

Houdini GL2.1 built-in functions

Houdini will automatically load and link the following GLSL functions if they are found in the GL2.1 shader code. All the methods are fragment shader specific unless otherwise noted.

void HOUassignOutputs(vec3 emit, vec3 amb, vec3 diff, vec3 spec, float shiny, vec3 P, vec3 N, float alpha)

Assigns the various RGB lighting components to the output color. Additional information, such as P (point position in view space), N (normal), shiny (specular shininess) and alpha (opacity) is required for proper shading in High Quality Lighting and Transparency rendering modes.

void HOUassignDiffuseOnly(vec3 diff, vec3 P, vec3 N, float alpha)

Assigns only the diffuse component. All other components are assumed to be zero. Point, Normal and alpha are required for High Quality Lighting and Transparency passes.

void HOUassignEmissionOnly(vec3 emit, float alpha)

Assigns the emission of the object along with the opacity. This is also used when the shader computes its own illumination, or doesn’t want its color affected by further lighting calculations.

Note

All fragment shaders must use exactly one of the HOUassign methods to write out their color values, instead of directly writing to gl_FragColor or gl_FragData[].

float HOUdiffuse(vec3 P, vec3 N)

Computes the diffuse illumination given point position P (in view space) and normal N.

void HOUlightDiffSpec(in vec3 P, in vec3 N, inout float diff, inout float spec, in float shiny)

Computes the specular and diffuse intensities for all lights in the scene (up to gl_MaxLights) given point position P, normal N and material shininess shiny. The results are added to the diff and spec parameters.

HOUlightingModel(in vec3 P, in vec3 N, inout vec4 amb, inout vec4 diff, inout float spec, in float shiny)

Computes the ambient, diffuse and specular colors for all lights in the scene (up to gl_MaxLights), given point position P, normal N, and material shininess shiny. The results are added to the amb, diff and spec parameters.

vec3 HOUfaceForward(vec3 N, vec3 P)

Returns the normal N if the polygon is forward facing, or -N if it is not. Point position P is required for OpenGL implementations with a broken gl_FrontFacing attribute, which this function attempts to mask.

void HOUdepthPeel(vec3 P)

Discards the fragment if the fragment fails the depth peel test. P is the pixel point position in view space.

float HOUsampleDepth(vec2 pos, int sample)

Returns the depth from UV coordinate pos using the depth map attached to the uniform variable depthMap. If multisampled rendering is enabled, sample represents the sample index to fetch. This is generally not used by user GLSL programs, but can be used in a vertex shader.

vec3 HOUsampleNormal(vec2 pos, int sample)

Returns the normal from UV coordinate pos using the normal map attached to the uniform variable normalMap. If multisampled rendering is enabled, sample represents the sample index to fetch. This is generally not used by user GLSL programs, but can be used in a vertex shader.

Houdini GL 3.2 built-in functions

The GL3.2 viewport has similar fragment shader functions, but also includes geometry shader functions for doing polygon outlining and attribute lookups.

Fragment shader functions

void HOUassignLitOutput(vec3 point_color,vec3 emit,vec3 amb,vec3 diff,vec3 spec,vec4 wire,float alpha,float selected)

Composites the lighting components, applies any Houdini shading (such as ghosting) and assigns the result to the fragment shader out in normal lighting mode (glH_MaterialPass is 0). The normal renderer is a forward renderer (all lighting computed on all shaded pixels).

void HOUassignMaterialOutput(vec3 point_color,vec3 emit_color,vec3 amb_color,vec3 diff_color,vec3 spec_color,float alpha,float emit_alpha,float shiny,vec4 wire,vec3 nN,float z,float selected)

Assigns the lighting components to the g-buffer outputs for the high quality lighting mode (glH_MaterialPass is 1). The High Quality lighting renderer is a deferred shading renderer (all parameters required for lighting and shading is stored in multiple buffers, and lights are processed after all geometry is rendered).

void HOUapplyLightMaps(inout vec3 nN, inout vec3 mspec, inout float shiny,bool has_bump_map, bool has_spec_map, vec2 bumpCoords, vec2 specCoords, float bumpScale, int bumpComps, bool bumpBias, bool bumpInvert, vec2 bumpMapSize, bool specularShinyAdjust, vec2 shinyRange)

Computes the normal (nN), material specular color component (mspec) and material shininess (shiny) from the specular, bump and normal maps.

void HOUfastLightingModel(in vec3 P,in vec3 nN,inout vec3 lAmb,inout vec3 lDiff,inout vec3 lSpec,in float sh)

Computes the lighting components aAmb, lDiff, and lSpec (ambient, diffuse and specular) using the first 3 scene lights (or headlight). This should only be used when rendering normal lighting (glH_MaterialPass is 0).

void HOUlightingModel(in vec3 P,in vec3 nN,inout vec3 lAmb,inout vec3 lDiff,inout vec3 lSpec,in float sh)

Computes t he lighting components in the same way as HOUfastLightingModel but for the first 9 scene lights (or headlight). This should only be used when rendering normal lighting (glH_MaterialPass is 0).

float HOUwireAlpha(vec3 edgedist, int edgeflag, float cut)

Given the edge distances and flags for all 3 triangle edges (x,y,z), and cutoff tolerance for the inner (non-AA) section of the line, compute an alpha for a pixel within a rendered triangle. This creates outlined triangles based on glH_WireThickness.

vec4 HOUwireColor(vec3 edgedist, int edgeflag, float selected)

Similar to HOUwireAlpha(), this computes the wire color and AA for outlining a triangle. The selected parameter allows mixing between the glH_SelectionColor and the glH_WireColor.

Geometry shader functions

vec3 HOUedgeDistance(vec4 v0, vec4 v1, vec4 v2, out int edges))

Given the three vertices in clip space of a triangle within a tessellated polygon, compute the edge flags (edges) and edge distances (return value) to be used by HOUwireColor() or HOUwireAlpha() in the fragment shader. The edge distances are in screen pixels. The edge flags are bits in the integer which indicate if that edge is an interior edge (zero, crosses the polygon) or an exterior edge (one, lies along a polygon edge). The edge bits are 1 (v1-v2), 2 (v0-v2) and 4 (v0-v1).

int HOUedges(vec4 v0, vec4 v1, vec4 v2)

A stripped down version of HOUedgeDistance(), this only returns the edge flags for the triangle within a tessellated polygon.

bool HOUfrustumCull(vec4 v0, vec4 v1, vec4 v2)

Returns true if the triangle with vertices v0, v1 and v2 (in clip space) is outside the current viewing frustum. This is a fast check, and some cases which are actually outside the viewing frustum may return false. In no cases will a triangle that is within the viewing frustum ever return true.

int HOUprimitiveID(out ivec3 vertices)

Returns the primitive ID for the current triangle, line or point. The vertices parameter returns the vertex indices for accessing vertex attributes stored within a texture or texture buffer object.

int HOUprimitiveIDEdges(out ivec3 vertices, out int edgeflags)

This is a combination of HOUprimitiveID() and HOUedges(). It returns the primitive index and vertices' indices as in HOUprimitiveID(), and the edge flags as in HOUedges(). It is slightly faster than calling both.

int HOUvertexID(out ivec3 vertices)

Returns a bitfield that provides some information about the current triangle, and sets vertices to the local vertex numbers of the polygon (always in the range zero to number of polygon vertices minus one). This is different from the vertices parameter in HOUprimitiveID(), which returns the vertex offsets within an attribute (zero to number of detail vertices minus one). The returned bitfield provides the following polygon tessellation information for the current triangle:

  • 0×01: first triangle in the polygon

  • 0×02: middle triangle in the polygon

  • 0×04: last triangle in the polygon

  • 0×08: polygon has an odd number of triangles

  • 0×10: vertex 1 has not already been used in this polygon

  • 0×20: vertex 2 has not already been used in this polygon

  • 0×40: vertex 3 has not already been used in this polygon

This can be used to position primitive and vertex decorations and estimate the centroid of the polygon.

Houdini auto-uniforms

Houdini automatically generates values for the following uniforms (all prefixed with glH_) which may be used by all shader stages.

glH_MaterialPass

An integer that stores the current pass being render. These passes are:

  • 0 - normal lighting pass

  • 1 - high quality lighting pass

  • 2 - high quality pass #2 (GL2.1 only)

  • 3 - shadow map pass

Lighting calculations should only be performed if glH_MaterialPass is 0. Basic material properties (diffuse, ambient, specular and emission) only need to be provided for pass #1, while Normals only need to be provided for pass #2. Pass #3 only requires alpha and depth.

glH_ViewMatrix

The view matrix (not to be confused with OpenGL’s modelview matrix). In GL2.1, this includes the object’s transform. In GL3.2, the view matrix is only the viewport tumble transform, as the object resides in glH_ObjectMatrix.

glH_InvViewMatrix

The inverse of the view matrix (not to be confused with OpenGL’s modelview matrix).

glH_ObjectMatrix (GL3.2 only)

The object transform for the geometry.

glH_ProjectMatrix

The transform used to convert camera space coords to clip space coords (which are -1,1 for X,Y, and Z).

glH_InvProjectMatrix

The inverse of the projection matrix, used to convert clip coords back into camera space.

glH_NumSamples

The number of samples in a multisampled (2x, 4x, 8x AA) buffer.

glH_LightEnabled (GL2.1 only)

An array that indicates which of OpenGL’s lights are enabled. glH_LightEnabled[i] is non-zero if (GL_LIGHT0 + i) is enabled.

glH_LightingEnabled

An integer that is either 1 if lighting is enabled, or zero if not.

glH_LightMask (GL3.2 only)

A int32 bitmask of lights that are enabled. The first scene light has bit 1, the second bit 2 (0×2), the third bit 3 (0×4), etc.

glH_ScreenSize

A vec2 containing the current dimension of the viewport being rendered.

glH_WireOver (GL3.2 only)

An integer set to one when a wireframe should be drawn over the model, and zero otherwise.

glH_WireColor (GL3.2 only)

The constant color of the wireframe overlay. This can change colors based on selection, template drawing or ghosting.

glH_WireThickness (GL3.2 only)

The current wire thickness, based on the display option setting, which may change depending on the selection status.

glH_ConstColor (GL3.2 only)

The constant color for drawing modes such as Hidden Line Invisible and Ghost.

glH_IsOrtho (GL3.2 only)

An integer set to zero if the view is perspective, or one if orthographic.

glH_SelectMode (GL3.2 only)

The current compoent selection display mode:

  • 0: nothing selected

  • 1: primitives, some selected

  • 2: primitives, all selected

  • 3: points, some selected

  • 4: points, all selected

  • 5: vertices: some selected

  • 6: vertices: all selected

Point, primitive and vertex group selections are treated as point, primitive and vertex selections, respectively.

The follow uniforms are available, but generally only used by the HOUassign() family of built-in Houdini functions. If you do not use them (not recommended) you will need to multiply in the factors, apply the ghost color, handle the depth peeling and two-sided lighting for transparency.

glH_Emission

A float that is 1.0 if emission is used in this pass, 0.0 if not.

glH_Specular

A float that is 1.0 if specular is used in this pass, 0.0 if not.

glH_Diffuse

A float that is 1.0 if diffuse is used in this pass, 0.0 if not.

glH_Ambient

A float that is 1.0 if ambient is used in this pass, 0.0 if not.

glH_GhostColor

A vec4 representing the ghosting color for 'ghost other objects' display mode. It is set regardless of whether the current object is ghosted, though the color will be (0,0,0,0) if the object is not ghosted.

glH_SelectColor

The current selection color, which can change depending on the selection type (object, component, closure, secondary).

glH_DepthPeelEnable (GL2.1 only)

An integer that is 1 when depth peeling is active, 0 otherwise.

glH_DepthPeelMap (GL2.1 only)

A 2D texture sampler containing the depth map for depth peeling.

glH_AlphaPass

An integer that is 1 when a transparency pass is active, 0 otherwise. Transparency passes always light the polygon face that is facing the light. This is used by the HOUlightingModel(), HOUdiffuse() and HOUlightDiffSpec() lighting methods.

Coding guidelines

Houdini’s viewport renderer has a large number of display settings which users can change. In some cases the viewport renderer renders multiple passes in order to create a certain visual effect. For example, projective textures and shadows both require multiple passes.

To be compatible with Houdini’s various rendering modes, GLSL shaders should adhere to the following guidelines:

  • Use one of the HOUassign...() methods to assign the color output of a fragment shader.

  • Do GL lighting with HOUlightingModel(), HOUdiffuse() or HOUlightDiffSpec(). Otherwise, only add light contributions from enabled light sources. Use the glH_LightEnabled or glH_LightMask uniform to check which lights are enabled.

The multi-pass viewport render

When writing a GLSL shader in Houdini it is useful to understand the contexts in which the shader will be executed. The uniform glH_MaterialPass can be used to query the pass.

Normal Lighting Pass (0)

Ambient, diffuse, specular and emission components can all be calculated with full lighting. This may be done with the Houdini lighting functions or by the shader.

High Quality Lighting Pass (1)

The raw ambient, diffuse, specular and emissive components of the material should be defined but no lighting calculations should be applied. If a shader does not want to participate in HQ lighting, do the lighting computations and assign it to the emissive component.

Normal Pass (2)

Everything but the normal component is discarded. This is only used in the GL2.1 viewport.

Shadow Map Pass (3)

A shadow map is being created. Only the depth and alpha value are used, so all calculations for color can be avoided.

When shading, the glH_AlphaPass variable is set to 1 if a transparency pass is rendering. You may discard the fragment if your material uses transparency and glH_AlphaPass is 0, or if your material is opaque and glH_AlphaPass is 1.

Transparency

The OpenGL viewport renderer distinguishes between transparent and opaque materials. To properly render transparent objects, shaders must provide a hint to the renderer. Currently you do this by declaring a parameter of type float with the name "ogl_alpha".

GL3.2 Viewport

The GL3.2 viewport pushes many responsibilities to the GPU, in order to improve geometry update performance. This makes parts of the shaders a bit more complicated, such as the geometry shader. The geometry shader is required to lookup primitive and vertex attributes (the vertex shader can only lookup vertex attributes).

In addition, the GLSL built-ins are deprecated. These include the GL lighting uniforms, transform matrices (gl_ProjectionMatrix, gl_ModelviewMatrix), and the predefined vertex shader inputs and outputs (glVertex, glNormal, glColor, gl_MultiTexCoord#, gl_TexCoord). Instead, all information is passed through uniforms, uniform blocks, and named vertex inputs (P, Cd, Alpha, N) which correspond to their Houdini attribute names.

Besides the glH_ Houdini uniforms listed above, the GL3.2 viewport also recognizes uniform blocks. There is a limited number of uniform blocks available in any shader stage (see Help > About Houdini and Show Details, in the OpenGL information for COMBINED_VERT_UNIFORM_BLOCKS and others).

Material uniform block

The definition of a Houdini material. This may be used in any shader stage.

layout(std140) uniform material
{
    vec3            ambient_color;
    vec3            diffuse_color;
    vec3            emission_color;
    vec3            specular_color;
    float           material_alpha;
    float           shininess;
    bool            has_diffuse_map;
    
    bool            has_bump_map;
    int             bumpComps;
    vec2            bumpMapSize;
    bool            bumpBias;
    bool            bumpInvert;
    float           bumpScale;
    
    bool            has_spec_map;
    bool            specularShinyAdjust;
    vec2            shinyRange;
};

uniform sampler2D diffuseMap;
uniform sampler2D bumpMap;
uniform sampler2D specularMap;

Light uniform block

Basic information for scene lights. The trailing digit may be 0-9 for multiple lights. Check the glH_LightMask to see if that light should contribute.

layout(std140) uniform light0
{
    vec3        pos;
    vec3        dir;
    vec3        atten;
    vec3        amb;
    vec3        spec;
    vec3        diff;
    float       coscutoff;
    bool        point;
} lightSource0;

Applying an OpenGL shader

Assign a GLSL shader for the viewport only

Set an object’s surface shader to an instance of your GLSL shader, or connect an instance of your GLSL shader to the surface color output inside a material.

Assign both a GLSL shader for the viewport and a shader for the renderer
  • You can define both GLSL shader code and VEX or RenderMan code in a GLSL shader type. Houdini will use the GLSL code in the viewport and the VEX/RenderMan code in the render.

    On the Code tab, click the gear menu and turn on VEX/RenderMan shader. This creates another tab where you can write VEX or RenderMan shader code.

  • You can also connect both an OpenGL shader and VEX surface shader to the surface color output of a material using a Select shader node.

Troubleshooting

My Geometry is Invisible
  • Make sure that your GLSL shader compiles.

    Right click the shader node and choose Type properties. Click the Code tab. Click Test compile to try compiling your shader code and check for errors.

  • Some GLSL shaders require vertex attributes to be passed to them (e.g. the tangent space normal mapping shader). Make sure you are passing it the correct data.

My Geometry is Not Receiving Shadows

Some shaders emit light and don’t reflect light (e.g. the decal shader). Such a shader will, by design, not receive shadows.