[SESI logo]

VEX Language Reference - Version 7.0

Side Effects Software Inc. 2004

VEX Shading Contexts

  • Common Interface
  • Surface Context
  • Photon Context
  • Displacement Context
  • Light Context
  • Shadow Context
  • Fog Context
  • Special variables
  • Transform Spaces
  • Opacity vs. Alpha

  • Shading Contexts -- Common information

    The shading contexts share many common attributes. Each context represents a different stage in the rendering pipeline. Displacement shading is done first, followed by surface shading and then fog/atmosphere shaders are run. During surface and fog shading, light and shadow shaders may be run in order to compute illumination. The global variables which are used in the shading contexts are:

    Global Variables

    Variable Type Description
    Cf vector The final color for the surface. The vector represents the RGB color for the surface.
    Of vector The final opacity for the surface. A value of {1,1,0} will be opaque in red/green, but let through blue light from behind.
    Af float The final alpha for the surface. This is the value which is placed in the alpha channel of the output image.
    P vector The position of the point on the surface being shaded.
    In light or shadow shaders, the P variable contains the point on the light source
    Pz float The z component of the point being shaded.
    Ps vector In light & shadow shaders, this is the position of the point on the surface being illuminated.
    I vector The direction from the eye to the point being shaded. This may or may not be a normalized vector.
    Eye vector The position of the eye.
    s float The parametric s (sometimes called u) coordinate of the surface being shaded.
    t float The parametric t (sometimes called v) coordinate of the surface being shaded.
    dPds, dPdt vector The change in position with respect to the parametric coordinates s, t
    N vector The shading normal for the surface.
    Ng vector The geometric normal for the surface. This normal represents the "true" normal of the surface being shaded. For example, with Phong shading, the N variable represents the interpolated normal, while the Ng variable represents the true polygon normal
    Cl vector Light color
    L vector The vector from the point on the surface to the light source. The length of this vector represents the distance to the light source. Please see here for further information on how the L variable is initialized
    Lz vector The z-axis in the space of the light. This is a unit vector.

    Each context is responsible for setting or modifying different variables. For example, the displacement context can modify the position of the surface being rendered, while the light context is responsible for setting the color of the light source. The Read/Write access of the variables for each context can be described below.

    Global Variable Access

    Variable Displacement Surface Light Shadow Fog Photon
    Cf N/A Write N/A N/A Read/Write N/A
    Of N/A Write N/A N/A Read/Write N/A
    Af N/A Write N/A N/A Read/Write N/A
    P Read/Write Read/Write(*) Read Read Read Read
    Pz Read Read N/A N/A Read Read
    Ps N/A N/A Read Read N/A N/A
    I N/A Read Read Read Read Read
    Eye N/A Read Read Read Read Read
    s Read Read Read Read Read Read
    t Read Read Read Read Read Read
    dPds, dPdt Read Read Read Read Read Read
    N Read/Write Read/Write Read Read Read Read
    Ng Read Read Read Read Read Read
    Cl N/A Read/Write Write Read/Write Read/Write Read
    L N/A Read Read/Write Read Read Read
    Lz N/A N/A Read Read N/A Read
    * Although P is modifiable in the surface context, at the current time, changing P will not affect rendering of the surface, only shading.

    Common Shading Functions

    The following functions are available in all shading contexts.

  • float Du(float var, ...)
    vector Du(vector var, ...)
    vector4 Du(vector4 var, ...)
    Computes the derivative of the variable with respect to the s parametric coordinate. This is the change in the variable over the area being shaded.

    Additional arguments may be specified to control the derivative computation.

  • float Dv(float var, ...)
    vector Dv(vector var, ...)
    vector4 Dv(vector4 var, ...)
    Computes the derivative of the variable with respect to the t parametric coordinate. This is the change in the variable over the area being shaded.

    Additional arguments may be specified to control the derivative computation.

  • float area(vector var, ...)
    Computes the shading area of the variable. This is typically used to get a representation of the area being shaded in terms of pixels.

    Additional arguments may be specified to control the area computation.

  • float filterstep(float edge, x, ...)
    float filterstep(float edge, x0, x1, ...)
    Returns the anti-aliased weight of the step function. The step function returns 0 if x is less than edge and 1 if x is greater than edge. The filterstep() function will return a fraction representing the filtered area under the step function. Optionally an arbitrary
    filter kernel and width may be specified using the "filter" and "width" additional arguments in the same fashion as for texture() functions. Example: f = filterstep(0.5, s+t, "filter", "gauss", "width", 2); The first form is roughly equivalent to: f = filterstep(edge, x, x + abs(Du(x)+Dv(x)));

  • vector computenormal(vector P, ...)
    vector computenormal(vector P, N, Ng, ...)
    Computes the normal for the described by P. This is done performing the cross product of the derivatives of P. The second form takes the original surface normal and geometric normal. The computed normal will be "adjusted" so that interpolated normals will be relatively correct.

    Additional arguments may be specified to control the area computation.

  • string getobjectname()
    This function returns the name of the current "object" whose shader is being run. Within light/shadow contexts, this is the name of the light object which has the shader bound to it. For surface/displacement contexts, this function will return the name of the object being shaded. The function will also return the name of the atmosphere object being shaded from within fog shaders.

  • int renderstate(string query, int &value)
    int renderstate(string query, float &value)
    int renderstate(string query, vector &value)
    int renderstate(string query, vector4 &value)
    int renderstate(string query, matrix3 &value)
    int renderstate(string query, matrix4 &value)
    int renderstate(string query, string &value)

    This function queries the renderer about certain state information. If the renderer is unable to evaluate the query, then the function will return 0 (and the value variable will remain unchanged). If the renderer is able to provide information for the query, then the function will return non-zero and the value will be set to the result of the query. Currently, mantra supports the following queries:
    Query Return Type Description
    renderer:name string The name of the renderer.
    renderer:version string/vector The version of the renderer. The string returned will be of the form "major.minor.build". As a vector, this is returned with the major version number in the x component, the minor number in the y and the build number in the z component.
    image:name string The name of the image being rendered.
    image:resolution vector The three components of the vector will be set to the X resolution, the Y resolution and the total number of samples per pixel.
    image:samples vector The three components of the vector will be set to the number of X samples, the number of Y samples and 0.
    image:raysamples vector The three components will be set to the number of ray-tracing samples in X, Y and zero.
    object:name string The name of the object being shaded. This is valid within light and shadow shaders and can be used to query which object is being lit (or shadowed) by the light source.
    object:reflectscope string The default reflection scope pattern for the object being shaded.
    object:refractscope string The default refraction scope pattern for the object being shaded.
    object:reflectlimit float/int The hard limit for maximum reflection bounces for the object being shaded.
    object:refractlimit float/int The hard limit for maximum refraction bounces for the object being shaded.
    object:shadingquality float The shading quality for the object being shaded.
    light:name string The name of the light object which is currently active in the illuminance loop.
    light:shadowmask string The shadow mask of the light object currently active in the illuminance loop.
    shader:name string The name of the current shader being run.

    For example: surface showversion() { string rname, rversion; if (!renderstate("renderer:name", rname)) rname = "Unknown renderer"; if (!renderstate("renderer:version", rversion)) rversion = "Unknown version"; printf("Image rendered by %s (%s)\n", rname, rversion); } vector mapToScreen(vector NDC_P) { // Given a point in NDC space, find out which pixel it // maps to. vector result; if (!renderstate("image:resolution", result)) result = {640, 486, 0}; return result * NDC_P; }
  • void trace(vector &cv, &of; float ⁡ vector P, D; float bias, max_contrib, [options])
    This function will send a ray starting at P and in the direction specified by the normalized vector D. The resulting color, opacity and alpha will be returned. The bias parameter is typically a small number which is used to prevent self-shading of the trace() function. The max_contrib parameter is used to give the renderer an idea of how much the result of the trace() call will contribute to the resulting pixel color. The max_contrib parameter has no effect on the results of the trace() call.

  • float rayhittest(vector P, D; float bias, [options])
    float rayhittest(vector P, D; vector &pHit, &nHit; float bias, [options])
    This function will send a ray from the position P along the direction specified by the direction D. The length of the D vector represents the farthest distance considered when check for occlusion. The function will return the distance to the object intersected. If no object is hit, the distance will less than 0. If pHit and nHit are specified, they will be set to the position and normal of the hit surface.

    Note: Though it is possible, in many cases, the area sampling features will not produce usable results with the rayhittest() function.

  • float fastshadow(vector P, D; float bias, [options])
    This function will send a ray from the position P along the direction specified by the direction D. The length of the D vector represents the farthest distance considered when check for occlusion. The function will return 1 if there are no occluding objects found, or 0 if the ray hit any object in between.

  • vector filtershadow(vector P, D; float bias, [options])
    This function will send a ray from the position P along the direction specified by the direction D. The length of the D vector represents the farthest distance considered when check for occlusion. Each occluding surface will be evaluated and its opacity will be added to the total occlusion. The return code of this function is the total occlusion of shaded surfaces between the point P and the point specified by P+D.

  • int getraylevel()
    Returns the depth of the ray tree for the current shading. If the returned value is 0, this represents a ray from the camera to the scene. If the ray level is 1, the ray represents either a reflection/refraction ray. If the level is 2, then this represents a reflection/refraction which appears in a previous reflection/refraction etc.

  • float getrayweight()
    Returns the an approximation to the contribution of the ray to the final pixel color. Often, this is a better metric for judging contribution to the final pixel color than getraylevel(). However, this does rely on prior shaders giving good estimates on the contribution to their shading (see reflectlight()).

  • int getglobalraylevel()
    Returns the depth of the ray tree for computing global illumination. If this function returns a non-zero value, the shader is being called for the purpose of evaluating global illumination.

  • float specularBRDF(vector L, N, V; float rough)
    float phongBRDF(vector L, N, V; float rough)
    float blinnBRDF(vector L, N, V; float rough)
    float diffuseBRDF(vector L, N, V; float rough)
    float diffuseBRDF(vector L, N)
    These functions return the computed BRDFs for the different lighting models used in VEX shading. They can be used in custom illuminance() loops to replicate the lighting models of the corresponding VEX lighting functions. For example: vector nn = normalize(frontface(N, I)); vector ii = normalize(-I); Cf = 0; illuminance(P, nn) { vector ll = normalize(L); Cf += Cl * (specularBRDF(ll, nn, ii, rough) + diffuseBRDF(ll, nn)); } The diffuseBRDF(vector L, N) is equivalent to clamp(dot(L, N), 0, 1).

  • vector texture(string map; ...)
    vector texture(string map; float ss, tt; ...)
    vector texture(string map; float s0, t0, s1, t1, s2, t2, s3, t3; ...)
    vector4 texture(string map; ...)
    vector4 texture(string map; float ss, tt; ...)
    vector4 texture(string map; float s0, t0, s1, t1, s2, t2, s3, t3; ...)
    The texture() functions compute a filtered sample of the texture map specified. With no coordinates given, the values of the s and t variables are used to index the texture. The forms returning vector4 will have the alpha from the texture map in the fourth component.

    Additional arguments can be used to specify filtering options.

  • vector environment(string map; vector D)
    vector4 environment(string map; vector D)
    The map specified will be considered an environment map (on an infinite sphere). The color of the environment texture is returned.

    Additional arguments can be used to specify filtering options.

  • matrix otransform(string name);
    matrix ltransform(string name);
    matrix ftransform(string name);
    These functions query the scene for a geometry object, light or fog object of the given name. If the object is found, the transform matrix applied to that object is returned.

    Because of the way particle instancing is implemented for vmantra, the otransform function will return the transform for one and only one particle for the given object.

    When referring to objects which are contained in sub-networks, the path of the object (without the leading "/obj/") should be used to reference the object. This applies to objects, lights and atmosphere objects.

  • vector otransform(string name, vector);
    vector ltransform(string name, vector);
    vector ftransform(string name, vector);
    vector ontransform(string name, vector);
    vector lntransform(string name, vector);
    vector fntransform(string name, vector);
    vector ovtransform(string name, vector);
    vector lvtransform(string name, vector);
    vector fvtransform(string name, vector);
    These functions query the scene for a geometry object, light or fog object of the given name. If the object is found, the world space vector is transformed into the space of the given object. Otherwise, the vector remains unchanged. The n methods transform normal vectors, the v methods transform direction vectors. The base methods transform positions.


  • Area Sampling

    Many of the ray-tracing functions can perform area-sampling rather than point sampling. There are two optional parameters which control this behaviour.
    Parameter Functions Description
    "scope", string spec all
    This option allows an override of the scope for ray-intersections. More information on specification of scope can be found here.
    "bias", float value irradiance
    occlusion
    The irradiance and occlusion functions take an optional bias parameter which gives control over self-intersection.
    "maxdist", float value all This option allows an override of the maximum distance the ray can travel when testing for intersections. Some functions (i.e. fastshadow()) have the maximum distance implicitly defined (by the length of the ray) and should probably avoid using this option. However, this option can be used effectively when computing reflections, global illumination, refraction etc.
    "variance", float value reflectlight
    refractlight
    fastshadow
    filtershadow
    trace
    This option overrides the global variance control (mantra's -v option) which is used to determine anti-aliasing quality of ray tracing. For more information please refer to the documentation on mantra.
    "angle", float value reflectlight
    refractlight
    fastshadow
    filtershadow
    trace
    This value of this parameter specifies a cone angle over which samples will be distributed. To be effective, the samples parameter should also be specified. The value is specified in radians.
    "samples", int value reflectlight
    refractlight
    fastshadow
    filtershadow
    trace
    irradiance
    occlusion
    The value of this parameter tells how many samples should be sent out to filter rays. For the irradiance and occlusion functions, specifying a samples parameter will override the default irradiance sampling.
    "environment", string map reflectlight
    refractlight
    trace
    irradiance
    occlusion
    If the ray sent out to the scene misses everything, then it's possible to specify an environment map to evaluate. Using the ray's direction, the environment map specified will be evaluated and the resulting color will be returned. Most likely, it will be necessary to specify a transform space for the environment map evaluations.
    In the case of refractlight and trace the Of and Af variables will be set to 0 regardless of the background color specified. the resulting color.

    When an environment map is specified, the standard texture filtering options are also supported.

    "envobject", string objectname
    "envlight", string lightname
    "envfog", "string fogname
    reflectlight
    refractlight
    trace
    irradiance
    occlusion
    If an environment map is used, the orientation of the environment map can be specified by transforming the ray into the space of another object, light or fog object in the scene. In Houdini, null objects can be used to specify the orientation. For example: Cf = R*reflectlight(bias, max(R), "environment", "map.rat", "envobject", "null_object_name");
    "envtint", vector color reflectlight
    refractlight
    trace
    irradiance
    occlusion
    If an environment map is used, it's possible to "tint" the resulting color.
    "background", vector color reflectlight
    refractlight
    trace
    irradiance
    occlusion
    If a ray misses all objects, it's possible to specify the background color of the scene.
    In the case of refractlight and trace the Of and Af variables will be set to 0 regardless of the background color specified.
    "distribution", string style irradiance This determines the distribution for computing irradiance. The default is to use a cosine distribution (diffuse illumination). The possible values for the style are:
  • uniform - Uniform sampling
  • cosine - Cosine weighted sampling

  • For area sampling to occur, both the angle and sample parameters must be specified. For example: surface blurry_mirror(float angle = 3; int samples = 16; float bias=0.05) { Cf = reflectlight(bias, 1, "angle", angle, "samples", samples); } For reference, the following functions accept the area/samples parameters:
  • fastshadow()
  • filtershadow()
  • rayhittest()
  • reflectlight()
  • refractlight()
  • trace()

  • Ray-Intersection Scoping

    When sending rays, the list of objects to intersect against are typically limited by a "scope" which is specified in Houdini. For example, sending a reflection ray will limit the objects which are tested for ray-intersection to the objects which match the reflection mask of the reflective object. However, it is possible to override the scope of objects to perform intersection tests against by specifying an additional scope argument. For example,

    Cr = reflectlight(bias, max_contrib, "scope", "geo1,geo2"); will only cause objects "geo1" and "geo2" to be picked up in the reflections. All of the Houdini scoping rules (excepting group expansion) are supported:

  • * - wild-card match
  • ? - single character match
  • ^ - exclusion operator
  • [list] - character list match
  • Some example patterns are:
  • geo* - Matches all objects starting with "geo"
  • geo*,^geo2 - Matches all objects starting with "geo" except for "geo2"
  • leg*,arm[123] - Matches all objects starting with "leg" as well as "arm1", "arm2", and "arm3".
  • For reference these are the ray-intersection scopes used by default for each ray-tracing function.
    Function Light/Shadow Shader Surface Shader
    fastshadow() Light's shadow scope Object's reflection scope
    filtershadow() Light's shadow scope Object's reflection scope
    rayhittest() Light's shadow scope Object's reflection scope
    reflectlight() Object's reflection scope Object's reflection scope
    refractlight() All objects (scope = "*") All objects (scope = "*")
    trace() Object's reflection scope Object's reflection scope
    irradiance() Object's reflection scope Object's reflection scope
    occlusion() Light's shadow scope Object's reflection scope


    Illuminance Light Mask

    When evaluating light and shadow shaders, objects have pre-defined light masks. This mask is usually specified in the geometry object and specifies a list of lights which are used to illuminate a surface or fog shader. It is possible to override the default light mask by specifying a "lightmask" argument. For example: diff = diffuse(nml, "lightmask", "light*,^light2"); will cause all lights whose names begin with "light" except for a light named "light2" to be considered for diffuse illumination. All of the Houdini scoping rules (excepting group expansion) are supported:

  • * - wild-card match
  • ? - single character match
  • ^ - exclusion operator
  • [list] - character list match
  • If an empty string is passed as a lightmask, the default lightmask will be used.


    Derivative Arguments

    When functions are required to compute derivatives (i.e. computing texture coordinates for filtering of maps), there are options to control the quality of derivatives.

    Extrapolation of deriatives can be used to hint that derivatives are "smooth" across patch boundaries. In most cases this is true and if extrapolation is turned on, derivative computation should be exact for C2 surfaces. However, when the VEX variables are changing with a high frequency (i.e. a high frequency displacement map will cause high frequency changes to the P variable), extrapolation of derivative computation may cause exaggeration of discontinuities between patch boundaries.

    Derivative "smoothing" will cause the magnitude of the differentials to be adjusted non-uniformly over patches. This will usually help to get rid of patch discontinuities in displacement/textured shaders. However, in some odd cases, it may be desirable to turn this feature off.

    All of the functions which compute derivatives take additional arguments to allow tuning of the derivative computation:

    Keyword Values
    extrapolate Turns derivative extrapolation on or off (default is off)
    smooth Turns derivative smoothing on or off (default is on)
    Note: This option is only valid for shading contexts.

    Example: N = computenormal(P, "extrapolate", 1, "smooth", 0);

    Surface Shading Context

    The surface shading context's purpose is to set the final color, opacity and alpha of the surface being rendered. If the Of and Af varaibles are not set, they will default to 1. If the Af variable is not set, it will resolve to avg(Of). It is possible to set the Af variable to any arbitrary value, making it possible to build matte/cutout shaders.

    Inside the surface context, it is possible to loop through all light sources in the scene computing their illumination and shadows. This is done using the illuminance() construct. This creates will loop through all light sources, calling the light shader for each light source to ensure that the Cl and L variables are set properly. The shadow shader will not be called unless specifically requested. However, once the shadow shader has been called, the value of Cl will be changed for the duration of the surface shader. The shadow shader is automatically called when using any of the built-in lighting calls (i.e. diffuse(), specular(), ambient()). The structure of an illuminance clause is:

    ... illuminance(position, [axis], [angle], [light_typemask], [lightmask]) { // Here, Cl and L will be set to the value/direction for the // current light source. // To force the shadow shader to be called, simply uncomment // the following line: // // shadow(Cl); }

    The default value for the axis is the surface normal. The default value for the axis is PI/2. The default value for the light mask is LIGHT_DIFFUSE|LIGHT_SPECULAR (please see shading.h for the light definitions). The illuminance() statement will loop through all light sources which meet the criteria dot(L, axis) > cos(angle).

    Surface Shader Specific Functions

  • void shadow(vector &Cl)
    void shadow(vector &Cl; vector P, L)
    Call shadow shaders for the current light source. This function can only be called from within an illuminance() statement. Once the shadows have been computed for a light source, they are fixed for the duration of the shader.

  • vector ambient( [lightmask])
    Returns the color of ambient light in the scene.

  • vector irradiance(vector P, vector N, [options])
    Computes irradiance (global illumination) at the point P with the normal N.

  • vector occlusion(vector P, vector N, [options])
    Computes ambient occlusion at the point P with the normal N. Just as in the irradiance function, the hemisphere is sampled. However, unlike the irradiance function, surfaces which are intersected during the hemisphere sampling are not shaded. For this function to work properly, either a constant background color or an environment map must be specified in the optional scope parameters.

  • void occlusion(float &coverage, vector &missed_direction, [options])
    Instead of computing color information from ambient occlusion, this form of the occlusion() function will compute the coverage (the percentage of occlusion), and the average direction of empty space. The average direction can be used to lookup the color in a pre-blurred environment map.

  • vector diffuse(vector nml, [lightmask])
    vector diffuse(vector nml, V; float roughness, [lightmask])
    Returns the diffuse (Lambertian) illimination given the normalized surface normal. The second form uses the Oren-Nayar lighting model to compute the diffuse illumination for the surface. The Oren-Nayar lighting model is a more sophisticated lighting model than Lambertian lighting. The V vector represents a vector from the surface to the eye (i.e. -normalize(I)). With a roughness of 0, the Oren-Nayar lighting model is equivalent to the Lambertian model. As roughness increases toward 1, the illumination changes to mimic rougher materials (like clay). The Oren-Nayar form of diffuse() is more expensive than Lambertian diffuse lighting.

  • string getlightname()
    This function returns the name of the current light when called from within an illuminance loop.

  • vector phong(vector nml, V; float shinyness, [lightmask])
    vector blinn(vector nml, V; float roughness, [lightmask])
    vector specular(vector nml, V; float roughness, [lightmask])
    Returns the illumination for specular highlights using different lighting models. The V parameter represents the normalized vector from the surface to the eye (i.e. -normalize(I). shinyness is the Phong exponent (typically around 20 or higher). The roughness parameter represents the surface roughness (typically 0 to 1).

  • vector reflectlight(float bias, max_contrib, [options])
    vector reflectlight(vector P, D; float bias, max_contrib, [options])
    vector reflectlight(vector P, N, I; float bias, max_contrib, [options])
    Computes the amount of reflected light which hits the surface. The bias is typically a small number (i.e. 0.005) and is used to help eliminate self-reflection. The max_contrib is used to help the renderer get an idea of how much the reflected light will contribute to the final color of the pixel. This is typically the maximum of the reflection component of a lighting model. This has no effect on the resultant color. Typically, values less than 1 should be given.

    There are two "general" forms of reflectlight which take a position and direction; or a position, direction and incident ray. The latter computes the reflection vector.

    Example:

    surface mirror(vector refl_color=1; float bias=.005) { Cf = refl_color * reflectlight(bias, max(refl_color)); }
  • void refractlight(vector &cf, &of; float ⁡ vector P, D; float bias, max_contrib, [options])
    void refractlight(vector &cf, &of; float ⁡ vector P, N, I; float eta; float bias, max_contrib, [options])
    Computes the illumination of surfaces refracted by the current surface. The output color, opacity and alpha are computed and returned by these functions. The bias parameter is typically a small number and is used to prevent self-refraction. The max_contrib parameter is used to help the renderer get an idea of how much the refracted light will contribute to the final pixel color. This has no effect on the color returned by the refractlight() calls.

    The first form of the refractlight() function takes a position and direction, typically computed by the refract() or fresnel() functions.

    In order to prevent the renderer from computing standard transparency (i.e. non-refracted transparency), the Of variable must be set to {1,1,1} to make the surface "opaque". The Af variable can be set to any arbitrary value.

    Example:

    surface glass(float eta=1.3, bias = 0.005) { float Kr, Kt; vector R, T; vector cf, of; float af; frensel(normalize(I), normalize(N), eta, Kr, Kt, R, T); Cf = Kr * reflectlight(P, R, bias, Kr); refractlight(cf, of, af, P, T, bias, Kt); Cf += Kt * cf; Af = clamp(Kr + af*Kt, 0, 1); Of = 1; }
  • int isshadowray()
    Returns 1 if the shader is being called to evaluate opacity for shadow rays, 0 if the shader is being called to evaluate for surface color. This function can be used to compute different opacity if the surface is shadowing another surface.

  • int isfogray()
    Returns 1 if the shader is being called to evaluate illumination for fog objects, or 0 if the light or shadow shader is being called to evaluate surface illumination.

    This function is only valid inside light and shadow contexts and can be used to simplify light shaders when being evaluated for fog.

  • int dimport(string name; int &value)
    int dimport(string name; float &value)
    int dimport(string name; vector &value)
    int dimport(string name; vector4 &value)
    int dimport(string name; matrix3 &value)
    int dimport(string name; matrix &value)
    int dimport(string name; string &value)
    Imports a variable from the displacement shader for the surface. If the variable is not defined and exported, a value of 0 is returned by the function. Otherwise, a value of 1 is returned, and the value exported from the displacement shader is assigned to the variable.

  • int limport(string name; int &value)
    int limport(string name; float &value)
    int limport(string name; vector &value)
    int limport(string name; vector4 &value)
    int limport(string name; matrix3 &value)
    int limport(string name; matrix &value)
    int limport(string name; string &value)
    Imports a variable from the light shader for the surface. If the variable is not defined and exported, a value of 0 is returned by the function. Otherwise, a value of 1 is returned, and the value exported from the light shader is assigned to the variable. This function is only valid inside of an illuminance() loop.

  • int shimport(string name; int &value)
    int shimport(string name; float &value)
    int shimport(string name; vector &value)
    int shimport(string name; vector4 &value)
    int shimport(string name; matrix3 &value)
    int shimport(string name; matrix &value)
    int shimport(string name; string &value)
    Imports a variable from the shadow shader for the surface. If the variable is not defined and exported, a value of 0 is returned by the function. Otherwise, a value of 1 is returned, and the value exported from the light shader is assigned to the variable. This function is only valid inside of an illuminance() loop after the shadow shader has been invoked.


  • Photon Shading Context

    When mantra is generating photon maps, photon shaders are used instead of surface shaders. Thus, the photon context is very similar to the surface context. However, because of the behavioural differences between the contexts, most of the surface context specific functions are not valid in the photon context.

    When mantra is rendering a photon map, photons are spawned from light sources. Each photon represents a "bit" of energy that has left the light and will interact with the scene. When a surface is hit by a photon, the photon shader is invoked.

    When a photon hits a surface, a fraction of the photon's energy will be absorbed by the surface, and another portion of the energy will be reflected into the scene. For example, a mirror surface would absorb very little of the energy of the photon, but reflect a large amount of the energy back into the scene (creating a caustic effect), while a diffuse surface would be more likely to absorb energy, but might still distribute a fraction of the energy (creating color bleeding).

    However, to create "good" photon maps, all of the photons stored in the map should have roughly the same energy levels (otherwise filtering will be biased). Thus, instead of storing a fraction of the energy and distributing the remainder, the typical method distributing photons is to use a monte-carlo technique called "Russian Roulette". Rather than dealing with fractions of the energy, it's better to deal with fractions of photons. For example, instead of storing a photon with 30% of the incoming energy, instead, only store 30% of the photons which hit the surface (and reflect the other 70%).

    When a photon strikes a surface, there are four standard light paths for spawning new photons.

    1. The photon will be absorbed by the surface (terminating the light path).
    2. The photon will be reflected as diffuse light (diffuse light will scatter over the hemisphere above the surface)
    3. The photon will be reflected specularly (as in a mirror reflection)
    4. The photon will be refracted
    When a photon gets stored, it may be stored in one or more maps. Mantra keeps track of three individual maps:
    1. Direct Photon Map: If a photon is stored and has not undergone any bounces (i.e. getraybounce() == 0), the photon will be stored in the direct illumination map (if defined). Note that light sources may specify that their photons may not contribute to direct photon illumination.
    2. Caustic Photon Map: If a photon is stored and has undergone either specular reflection or transmission, it will be stored in the caustic photon map.
    3. Global Photon Map: Any photon which gets stored is added to the global photon map. Thus, the global photon map will contain all photons in the direct map, all caustic photons as well as any diffuse reflected photons. Note that light sources may specify that their photons may not contribute to direct photon illumination.
    In some ways, the structure of the photon shader is dependent on how the photon map will be accessed. Typically, the photon map will store incoming illumination. That is, photons directly from the light sources, or indirectly from other surfaces. Before a photon is reflected from the photon shader, the "color" of the surface would be used to modulate the photon color. That is, if the surface were red, the photon color would be tinted red.

    However, it's also possible to pre-compute the combined illumination The meaning of the global variables in the photon context are:

    Photon Global Variables

    Variable Description
    P The position on the surface being shaded (similar to the surface context).
    Pz The Z coordinate of P
    I The incoming direction of the photon.
    Eye The origin of the photon (the light source or reflecting surface).
    s, t The parametric coordinates of the surface being shaded.
    dPds, dPdt The surface derivatives.
    N, Ng The interpolated and geometric normal at the point being shaded.
    Cl The incoming energy of the photon.
    L The direction from the light to the surface (this is the same as I, but may have a different magnitude).
    Lz The Z-axis in the space of the light.

    Photon Shader Specific Functions

  • int photon_switch(float diff, spec, transmit)
    This function takes three arguments which represent the probabilities for each of the reflective paths. The probabilities should add up to a number less than or equal to one. Based on the probabilities, one of the four paths will be returned. There are defines available in <shading.h> which set: #define PHOTON_STORE 0 #define PHOTON_DIFFUSE 1 #define PHOTON_REFLECT 2 #define PHOTON_TRANSMIT 3 For example, result = photon_switch(.2, .1, .3); will have result set to PHOTON_DIFFUSE(1) 20% of the time, PHOTON_REFLECT(2) 10%, PHOTON_TRANSMIT(3) 30% of the time and will return PHOTON_STORE(0) the rest of the time (40%).

  • void photon_diffuse(vector P, N, Cl)
    This generates a new diffuse photon path. The path will be randomly distributed over the hemisphere defined by P and N. The photon will have the energy Cl.

  • void photon_reflect(vector P, R, Cl)
    This generates a new specular photon path. The path is defined by the ray starting at P and travelling along R (the reflection direction).

  • void photon_transmit(vector P, R, Cl)
    This generates a new transmission photon path. The path is defined by the ray starting at P and travelling along R (the refraction direction).

  • void photon_store(vector P, N, Cl, I)
    Store a photon in the appropriate maps. The position, normal, energy and incident direction are used when filtering the photons (using the
    photonmap function).


  • Displacement Shading Context

    Displacement shading can be used to move the position of the surface before the surface gets rendered. It is intended as a mechanism to add fine detail to a surface, not as a modelling technique. After moving a surface, you must typically re-compute the normals of the surface. For surfaces which have interpolated normals (i.e. polygons which are smooth shaded), the computenormal(vector P, N, Ng) method can be used to approximate what the "smooth" displaced normal will be.

    There are no functions specific to displacement shading.


    Light Shading Context

    Light shaders will get called from surface or fog shaders to compute the illumination from a given light source. The light shader can be invoked using the illuminance() loop or using the standard diffuse(), specular(), etc. functions.

    Light Shader Specific Functions

  • int dimport(string name; int &value)
    int dimport(string name; float &value)
    int dimport(string name; vector &value)
    int dimport(string name; vector4 &value)
    int dimport(string name; matrix3 &value)
    int dimport(string name; matrix &value)
    int dimport(string name; string &value)
    Imports a variable from the displacement shader for the surface. If the variable is not defined and exported, a value of 0 is returned by the function. Otherwise, a value of 1 is returned, and the value exported from the displacement shader is assigned to the variable.

  • vector irradiance(vector P, vector N, [options])
    This is identical to the function in the surface context.

  • vector occlusion(vector P, vector N, [options])
    void occlusion(float &coverage, vector &miss_direction, vector P, vector N, [options])
    These is identical to the function in the surface context.


  • Shadow Shading Context

    Shadow shaders will get called from surface or fog shaders to occlude the illumination from a given light source. The light will already have been computed by calling the light shader. The function of a shadow shader is to modify the Cl variable. Typically, the light will be occluded, causing the Cl variable to decrease in intensity. However, it is possible to create "negative" shadows, and increase the illumination due to occlusion.

    The shadow context is typically used to separate illumination from expensive ray-tracing calls (like fastshadow() or filtershadow()). This allows fog shaders (or surface shaders) to bypass shadow testing.

    Shadow Shader Specific Functions

  • int dimport(string name; int &value)
    int dimport(string name; float &value)
    int dimport(string name; vector &value)
    int dimport(string name; vector4 &value)
    int dimport(string name; matrix3 &value)
    int dimport(string name; matrix &value)
    int dimport(string name; string &value)
    Imports a variable from the displacement shader for the surface. If the variable is not defined and exported, a value of 0 is returned by the function. Otherwise, a value of 1 is returned, and the value exported from the displacement shader is assigned to the variable.

  • int limport(string name; int &value)
    int limport(string name; float &value)
    int limport(string name; vector &value)
    int limport(string name; vector4 &value)
    int limport(string name; matrix3 &value)
    int limport(string name; matrix &value)
    int limport(string name; string &value)
    Imports a variable from the light shader for the surface. If the variable is not defined and exported, a value of 0 is returned by the function. Otherwise, a value of 1 is returned, and the value exported from the light shader is assigned to the variable.


  • Fog Shading Context

    A fog shader is responsible for modifying the Cf, Of or Af variables after the surface shader has completed its shading. It is possible to use illuminance() statements inside of fog shaders.

    Fog Shader Specific Functions

  • int dimport(string name; int &value)
    int dimport(string name; float &value)
    int dimport(string name; vector &value)
    int dimport(string name; vector4 &value)
    int dimport(string name; matrix3 &value)
    int dimport(string name; matrix &value)
    int dimport(string name; string &value)
    Imports a variable from the displacement shader for the surface. If the variable is not defined and exported, a value of 0 is returned by the function. Otherwise, a value of 1 is returned, and the value exported from the displacement shader is assigned to the variable.

  • int limport(string name; int &value)
    int limport(string name; float &value)
    int limport(string name; vector &value)
    int limport(string name; vector4 &value)
    int limport(string name; matrix3 &value)
    int limport(string name; matrix &value)
    int limport(string name; string &value)
    Imports a variable from the light shader. If the variable is not defined and exported, a value of 0 is returned by the function. Otherwise, a value of 1 is returned, and the value exported from the light shader is assigned to the variable. This function is only valid inside of an illuminance() loop.

  • int shimport(string name; int &value)
    int shimport(string name; float &value)
    int shimport(string name; vector &value)
    int shimport(string name; vector4 &value)
    int shimport(string name; matrix3 &value)
    int shimport(string name; matrix &value)
    int shimport(string name; string &value)
    Imports a variable from the shadow shader. If the variable is not defined and exported, a value of 0 is returned by the function. Otherwise, a value of 1 is returned, and the value exported from the light shader is assigned to the variable. This function is only valid inside of an illuminance() loop after the shadow shader has been invoked.

  • int simport(string name; int &value)
    int simport(string name; float &value)
    int simport(string name; vector &value)
    int simport(string name; vector4 &value)
    int simport(string name; matrix3 &value)
    int simport(string name; matrix &value)
    int simport(string name; string &value)
    Imports a variable from the surface shader. If the variable is not defined and exported, a value of 0 is returned by the function. Otherwise, a value of 1 is returned, and the value exported from the surface shader is assigned to the variable.

  • string getlightname()
    This function returns the name of the current light when called from within an illuminance loop.


  • Initialization of the L Variable

    In the Light and Shadow contexts, the P variable represents the position of the light source and the Ps variable represents the position of the surface point being shaded.

    In Houdini, lights can have either perspective or orthographic projections. An orthographic light in Houdini is used to represent an infinite (or very distant) light source which has all the light rays parallel with each other. A perspective light acts more as a point light source.

    When a perspective light shader runs, the L variable is initialized as follows:

    L = P - Ps; Orthographic lights, on the other hand, are initialized so that the direction of L is the same for each light ray eminating from the light source. L = Lz * dot(Lz, P - Ps); Where Lz represents the normalized "z-axis" of the light source (i.e. a unit vector pointing down the z-axis in the space of the light). Thus, the scale of the L variable will be the orthographic distance from the plane of the light source and the surface point being shaded.

    In a light shader, it is possible to change the L variable to any value you choose. However, this is how the L variable is initialized.


    Special Variables

    There are several "special" variables used in the shading contexts. These special variables are specified as parameters to shaders. Typically, these are export parameters.

    Variable Context Description
    __nondiffuse Light If this variable is set to a non-zero value, the light shader will not contribute to diffuse illumination in the standard diffuse() functions.
    __nonspecular Light If this variable is set to a non-zero value, the light shader will not contribute to specular illumination in the standard phong(), blinn(), or specular() functions.
    __nofog Surface If this variable is set to a non-zero value, no fog shaders will affect the surface color.

    Transform Spaces

    One of the key features of VEX shading is the concept of spaces. There are at least two or three transform spaces defined for each context. Often, shading it is important to transform a position or vector in one space to a different space. This is done using the wt_space(), wo_space(), etc. functions. However, it is important to know what space variables are in and to which space the transform functions will take a variable.

    In all VEX contexts, global variables are in "world" space. In the mantra renderer, this space is defined with the camera at the origin pointing down the positive Z axis. Each shader has a local "object" space associated with it. This is the space which defined as the object at the origin of the space. Displacement, Surface and Light shaders also have a special "NDC" space associated with them.

    Context Space Description
    Displacement
    Surface
    World The space which has the camera at the origin, looking down the positive Z axis.
    Displacement
    Surface
    Shader Often, this is the same as object space. However, in Houdini, it is possible to define different spaces for displacement/surface shading. The functions wt_space(), wt_vspace(), wt_nspace() will transform from world to texture space. Typically, this space should be used for shading purposes.
    Displacement
    Surface
    Object This is defined as the space which has the object at its origin. This is basically the inverse of the object's transform. To get from world to object space, use wo_space(), wo_vspace(), wo_nspace().
    Displacement
    Surface
    NDC This is a special "Normal Device Coordinate" space. A position in world space can be converted to NDC space by calling the toNDC() function. This will transform the X & Y components of the position so that {0,0,z} will be the bottom left hand corner of the image plane as viewed from the camera. The top right hand corner will be represented by {1,1,z}. The Z component of the position remains unchanged by the NDC transformations. Given a point in NDC space, it is possible to find it's world space position by calling fromNDC().
    Light
    Shadow
    World The space which has the camera at the origin, looking down the positive Z axis.
    Light
    Shadow
    Shader For Light & Shadow contexts, this is the same as object space.
    Light
    Shadow
    Object This is defined as the space which has the light at the origin, pointing down the positive Z axis.
    Light
    Shadow
    NDC Since light sources in Houdini have the same attributes as cameras, NDC space is defined for light sources as well. To transform a position into the NDC space for the light source, the object space position should be used in the toNDC space call. The Z component of the object space position will remain unchanged. Given a point in NDC space, it is possible to find it's world space position by calling fromNDC().
    Fog World The space which has the camera at the origin, looking down the positive Z axis.
    Fog Shader For fog shaders, this is the same as object space.
    Fog Object This is defined as the space which has the fog object at the origin, pointing down the positive Z axis.
    Fog NDC This is a special "Normal Device Coordinate" space. A position in world space can be converted to NDC space by calling the toNDC() function. This will transform the X & Y components of the position so that {0,0,z} will be the bottom left hand corner of the image plane as viewed from the camera. The top right hand corner will be represented by {1,1,z}. The Z component of the position remains unchanged by the NDC transformations. Given a point in NDC space, it is possible to find it's world space position by calling fromNDC().

    Opacity vs. Alpha

    In the surface shader context, there are two separate variables to control transparency. Of and Af are related, but represent different quantities. The Of variable represents the opacity of the surface. For example, Of = {1, 0, 0}; will make the surface opaque in red, but pass through green and blue light from behind. This will give you a cyan colored filter. The opacity is used when mantra is resolving surface colors.

    The Af variable is used to decide what value gets put into the alpha channel of an RGBA image. If the Af variable is not set by a shader, it is automatically assigned by using:

    Af = avg(Of) However, because this variable is available, it is possible for a shader to decide what value gets put in the alpha channel of the output image. This makes it possible to write shaders like "matte" or "shadowmatte".

    For example, the following shader simulates a blue screen:

    surface bluescreen(vector clr=0) { Cf = clr; Of = 1; Af = 0; } The color of the surface is set to black (by default). The opacity is 1, meaning that this surface will occlude other surfaces in the scene. However, the alpha output to the image will be 0. This means that if this image is composited over an other image, the background image will blend appear where this surface was rendered. An example use of this would be to create a window in a wall without having to modify the geometry.

    It is also possible to set the Af variable to be something other than 1, meaning that the background image will appear "shadowed" where the matte surface is rendered. This is the theory behind the "shadowmatte" shader.



    Copyright © 1999-2004 Side Effects Software Inc.
    477 Richmond Street West, Toronto, Ontario, Canada M5V 3E7