next up previous contents
Next: 3.22 Initialization and Cleanup Up: 3. Using and Writing Previous: 3.20 Contours

Subsections

3.21 Functions for Shaders

mental ray makes a range of functions available to shaders that can be used to access data, cast rays, looking up images, and perform standard mathematical computations. The functions are grouped by the module that supplies them. The shader writer may also use C library functions, but it is mandatory to include <stdio.h> and <math.h>  if printing functions such as fprintf (use  mi_info or similar for console debugging messages) or math functions such as sin are used. Not including these headers may abort rendering at runtime, even though the compiler did not complain. All shaders must include the standard mental ray header file, shader.h.

All functions and features supported only by mental ray 2.1 and later but not by 2.0 are marked ``2.1''.

Here is a summary of functions provided by mental ray. Section [*] shows which functions can be used in which shaders.

 


Shader Calls

type name arguments
miBoolean mi_call_shader *result, type, *state, tag
miBoolean mi_call_shader_x *result, type, *state, tag, *arg
miBoolean mi_call_material *result, *state
miBoolean mi_call_photon_material *result, *state
void * mi_eval *state, *param
miBoolean * mi_eval_boolean *param
miInteger * mi_eval_integer *param
miScalar * mi_eval_scalar *param
miVector * mi_eval_vector *param
miScalar * mi_eval_transform *param
miColor * mi_eval_color *param
miTag * mi_eval_tag *param
void mi_flush_cache *state


DB

type name arguments
int mi_db_type tag
int mi_db_size tag
void * mi_db_access tag
void mi_db_unpin tag
void mi_db_flush tag


RC Functions

type name arguments
miBoolean mi_trace_eye *result, *state, *org, *dir
miBoolean mi_trace_reflection *result, *state, *dir
miBoolean mi_trace_refraction *result, *state, *dir
miBoolean mi_trace_transparent *result, *state
miBoolean mi_trace_environment *result, *state, *dir
miBoolean mi_trace_probe2.1 *state, *dir, *org
miBoolean mi_trace_light *result, *dir, *nl, *st, i
miBoolean mi_sample_light *result, *dir, *nl, *st,i,*s
miBoolean mi_trace_shadow *result, *state
miBoolean mi_trace_shadow_seg *result, *state
miBoolean mi_compute_irradiance *result, *state
miBoolean mi_compute_volume_irradiance *result, *state
miBoolean mi_sample2.1 *sample, *i, *state, dim, *n


RC Photon Functions

type name arguments
miBoolean mi_photon_light *energy, *state
miBoolean mi_photon_reflection_specular *energy, *state, *dir
miBoolean mi_photon_reflection_glossy2.1 *energy, *state, *dir
miBoolean mi_photon_reflection_diffuse2.1 *energy, *state, *dir
miBoolean mi_photon_transmission_specular *energy, *state, *dir
miBoolean mi_photon_transmission_glossy2.1 *energy, *state, *dir
miBoolean mi_photon_transmission_diffuse2.1 *energy, *state, *dir
miBoolean mi_photon_transparent *energy, *state
miBoolean mi_photon_volume_scattering *energy, *state, *dir
void mi_store_photon *energy, *state
void mi_store_volume_photon *energy, *state


RC Direction Functions

type name arguments
void mi_reflection_dir dir, state
void mi_reflection_dir_specular *dir, *state
void mi_reflection_dir_glossy *dir, *state, shiny
void mi_reflection_dir_anisglossy *dir, *state, u, v, shiny_u, shiny_v
void mi_reflection_dir_diffuse *dir, *state
miBoolean mi_refraction_dir dir, state, ior_in, ior_out
miBoolean mi_transmission_dir_specular *dir, *state, *in, *out
miBoolean mi_transmission_dir_glossy *dir, *state, *in, *out, shiny
miBoolean mi_transmission_dir_anisglossy *dir, *state, *in, *out, u, v, shiny_u, shiny_v
void mi_transmission_dir_diffuse *dir, *state
void mi_scattering_dir_diffuse *dir, *state
void mi_scattering_dir_directional *dir, *state, directionality
miScalar mi_scattering_pathlength *state, density


IMG Functions

type name arguments
void mi_img_put_color *image, *color, x, y
void mi_img_get_color *image, *color, x, y
void mi_img_put_scalar *image, scalar, x, y
void mi_img_get_scalar *image, *scalar, x, y
void mi_img_put_vector *image, *vector, x, y
void mi_img_get_vector *image, *vector, x, y
void mi_img_put_depth *image, depth, x, y
void mi_img_get_depth *image, *depth, x, y
void mi_img_put_normal *image, *normal, x, y
void mi_img_get_normal *image, *normal, x, y
void mi_img_put_label *image, label, x, y
void mi_img_get_label *image, *label, x, y


Vector and Matrix Math Functions

type name arguments
void mi_vector_neg *r
void mi_vector_add *r, *a, *b
void mi_vector_sub *r, *a, *b
void mi_vector_mul *r, f
void mi_vector_div *r, f
void mi_vector_prod *r, *a, *b
miScalar mi_vector_dot *a, *b
miScalar mi_vector_norm *a
void mi_vector_normalize *r
void mi_vector_min *r, *a, *b
void mi_vector_max *r, *a, *b
miScalar mi_vector_det *a, *b, *c
miScalar mi_vector_dist *a, *b
void mi_matrix_null r
void mi_matrix_ident r
miBoolean mi_matrix_isident a
void mi_matrix_copy r, a
miBoolean mi_matrix_invert r, a
void mi_matrix_prod r, a, b
void mi_matrix_rot_det a
void mi_matrix_rotate a, x, y, z
void mi_matrix_rotate_axis a, *v, r


Transformation Math Functions

type name arguments
void mi_point_transform *r, *v, m
void mi_vector_transform *r, *v, m
void mi_vector_transform_T *r, *v, m
void mi_point_to_world *state, *r, *v
void mi_point_to_camera *state, *r, *v
void mi_point_to_object *state, *r, *v
void mi_point_to_light2.1 *state, *r, *v
void mi_point_to_raster *state, *r, *v
void mi_point_from_world *state, *r, *v
void mi_point_from_camera *state, *r, *v
void mi_point_from_object *state, *r, *v
void mi_point_from_light2.1 *state, *r, *v
void mi_vector_to_world *state, *r, *v
void mi_vector_to_camera *state, *r, *v
void mi_vector_to_object *state, *r, *v
void mi_vector_to_light2.1 *state, *r, *v
void mi_vector_from_world *state, *r, *v
void mi_vector_from_camera *state, *r, *v
void mi_vector_from_object *state, *r, *v
void mi_vector_from_light2.1 *state, *r, *v
void mi_normal_to_world *state, *r, *v
void mi_normal_to_camera *state, *r, *v
void mi_normal_to_object *state, *r, *v
void mi_normal_to_light2.1 *state, *r, *v
void mi_normal_from_world *state, *r, *v
void mi_normal_from_camera *state, *r, *v
void mi_normal_from_object *state, *r, *v
void mi_normal_from_light2.1 *state, *r, *v


Noise Functions

type name arguments
miScalar mi_random  
miScalar mi_srandom seed
miScalar mi_erandom seed[3]
double mi_par_random *state
miScalar mi_spline t, n, *ctl
miScalar mi_noise_1d p
miScalar mi_noise_2d u, v
miScalar mi_noise_3d *p
miScalar mi_noise_1d_grad p, *g
miScalar mi_noise_2d_grad u, v, *gu, *gv
miScalar mi_noise_3d_grad *p, *g
miScalar mi_unoise_1d p
miScalar mi_unoise_2d u, v
miScalar mi_unoise_3d *p
miScalar mi_unoise_1d_grad p, *g
miScalar mi_unoise_2d_grad u, v, *gu, *gv
miScalar mi_unoise_3d_grad *p, *g


Auxiliary Functions

type name arguments
miScalar mi_fresnel n1, n2, t1, t2
miScalar mi_fresnel_reflection *state, *i, *o
miScalar mi_phong_specular spec, *state, *dir
void mi_fresnel_specular *ns, *ks, s, *st,
    *dir, *in, *out
miScalar mi_blinn_specular spec, *state, *dir
miScalar mi_blong_specular spec, *state, *dir
miBoolean mi_cooktorr_specular *result, *di, *dr, *n, roughness, *ior
miScalar mi_ward_glossy *di, *dr, *n, shiny
miScalar mi_ward_anisglossy *di, *dr, *n, *u, *v, shiny_u, shiny_v
miScalar mi_schlick_scatter *di, *dr, directionality
miRay_type mi_choose_scatter_type *state, transp, *specular, *glossy, *diffuse
miInteger mi_choose_lobe *state, r
miBoolean mi_lookup_color_texture *col, *state, tag, *v
miBoolean mi_lookup_scalar_texture *scal, *state, tag, *v
miBoolean mi_lookup_vector_texture *vec, *state, tag, *v
miBoolean mi_lookup_filter_color_texture *col, *state, tag, *paras, ST
miBoolean mi_texture_filter_project p[3], t[3], *state, disc_r, space
miBoolean mi_texture_filter_transform ST, p[3], t[3]
miBoolean mi_tri_vectors *state, wh, nt, **a, **b, **c
miBoolean mi_query query, *state, tag, *result, ...
miBoolean mi_fb_put2.1 *state, fb, *data
miBoolean mi_fb_get2.1 *state, fb, *data
miBoolean mi_geoshader_add_result query, *state, tag, *result, ...
miBoolean mi_geoshader_tesselate *state, *leaves, source
miBoolean mi_geoshader_tesselate_end leaves
char * mi_string_substitute2.1 *new, *old, size


Obsolete Auxiliary Functions

These functions are obsolete; use  mi_query for future implementations.

type name arguments
void mi_light_info tag, *org, *dir, **paras
int mi_global_lights_info **tag
void mi_texture_info tag, *xres, *yres, **paras
void * mi_shader_info *state
int mi_instance_info *state, **paras, **p1, **p2, **p3


Contour Functions

miBoolean mi_get_contour_line *p1, *p2
void mi_add_contour_lines p1[], p2[], n


Memory Allocation

type name arguments
void * mi_mem_allocate size
void * mi_mem_reallocate mem, size
void mi_mem_release mem
void mi_mem_check  
void mi_mem_dump mod


Thread Parallelism and Locks

type name arguments
void mi_init_lock *lock
void mi_delete_lock *lock
void mi_lock lock
void mi_unlock lock
int mi_par_localvpu  
int mi_par_nthreads  
int mi_par_aborted  


Messages and Errors

type name arguments
void mi_fatal *message, ...
void mi_error *message, ...
void mi_warning *message, ...
void mi_info *message, ...
void mi_progress *message, ...
void mi_debug *message, ...
void mi_vdebug *message, ...


Shader Calls

Shaders can be called either explicitly, or implicitly by evaluating a shader parameter that may be assigned to the output of another shader.

 

    miBoolean mi_call_shader(
        miColor * const result,
        miShader_type   type,
        miState * const state,
        miTag           shader)

 

    miBoolean mi_call_shader_x(
        miColor * const result,
        miShader_type   type,
        miState * const state,
        miTag           shader,
        void            *arg)

These functions call the shader specified by the tag shader. The extended version passes the arg parameter as a fourth argument to the shader. The other version passes a null pointer as fourth argument to the shader.  mi_call_shader_x is slightly more efficient than  mi_call_shader.

The tag is normally a  texture shader or  light shader or some other type of shader found in the calling shader's parameter list. The caller must pass its own state and the shader type, which must be one of miSHADER_LENS, miSHADER_MATERIAL, miSHADER_LIGHT, miSHADER_SHADOW miSHADER_ENVIRONMENT miSHADER_VOLUME, and miSHADER_TEXTURE. The sequence of operations is:

1.
shader is written into state - > shader.

2.
If the called shader is dynamically loaded and has an init shader that has not been called yet, it is called now, with state as its only argument.

3.
The shader referenced by shader is called with three arguments: the result pointer, the given state, and the  shader parameters retrieved from shader.

4.
After the shader returns, state - > shader is restored to its old value.

The return value of the shader is returned. If the shader expects a result argument of a type other than miColor, the pointer must be cast to miColor when passed to  mi_call_shader. Note that the shader tag references an entire function call including  shader parameters as defined in the .mi file with a texture, light, or some other statement combining shading function and shader parameters; shader is not just a simple pointer or reference to a C function.

 

    miBoolean mi_call_material(
        miColor         *result,
        miState         *state);

Call the  material shader in state - > material.

 

    miBoolean mi_call_photon_material(
        miColor         *result,
        miState         *state);

Call the  photon shader in state - > material. This is intended for  photon volume shaders.

        

    void *mi_eval(
        miState         *state,
        void            *param)

    miBoolean *mi_eval_boolean(
        miBoolean       *param)

    miInteger *mi_eval_integer(
        miInteger       *param)

    miScalar *mi_eval_scalar(
        miScalar        *param)

    miVector *mi_eval_vector(
        miVector        *param)

    miScalar *mi_eval_transform(
        miScalar        *param)

    miColor *mi_eval_color(
        miColor         *param)

    miTag *mi_eval_tag(
        miTag           *param)

  Return the value of a  shader parameter. If the shader parameter value is a constant,  mi_eval returns its argument. If the parameter is assigned to another shader, call that shader and return a pointer to its return value (or the cached return value if it has been called recently). If the parameter is assigned to a phenomenon interface, return a pointer to the value in the interface. The latter two cases let shaders operate in the contexts of shader assignments and phenomena without needing knowledge of the context, which is automatically handled. The pointer remains valid until the shader returns, which avoids the need to copy a large returned data structure such as a color or array to temporary variables. Shaders should always access their parameters with  mi_eval. If parameters are accessed without  mi_eval and the parameter is assigned to another shader or an interface, the shader will see garbage.

The typed variants of  mi_eval are implemented as macros for the convenience of shader writers. They cast their argument to a void pointer, call  mi_eval, and recast the returned pointer to the appropriate type. They all make the assumption that the shader has a local variable state of type miState * in scope. Experience has shown that the typed variants make source code look much cleaner. Note that there is only one macro  mi_eval_tag that can be used for parameters of type shader, color texture, vector texture, scalar texture, light, material, and geometry. All typed variants have been designed to return the same type they accept as an argument.

Always use the correct simple type. For example, if the parameter has type color, it must be evaluated as a single color (probably using mi_eval_color). It is not possible to use four scalar evaluations to access the R, G, B, and A components separately. Also, by convention, arrays should be evaluated as a unit, evaluating two integers for the i_ index, the n_ member count, and the array itself. However, structures are not evaluated as a unit; a separate evaluation is necessary for every simple member it contains.

 

    void mi_flush_cache(
        miState         *state)

Prevents the cache from being used by future calls to  mi_eval. If  mi_eval calls another shader, the result is stored in a special cache in that other shader, which is normally flushed only when the entire shader graph returns. This means that the other shader will only ever be called once during the evaluation of a shader graph, and all  mi_evals are satisified from the cache. Notice that flushing applies to the entire sub-graph of shaders evaluated by this and future  mi_evals; there is no way to flush the cache of a single shader because that would leave its sub-shaders in a funny state. The result cache is still active for shaders which call  mi_flush_cache.

This is useful if the code calls a another shader more than once, such as a texture shader to sample a texture at three different locations to compute bump mapping gradients. Although the shader, if called with  mi_call_shader or  mi_lookup_color_texture, will get called each time, its sub-shaders inside the same phenomenon will not if these subshaders are called as the result of  mi_eval. (Remember that  mi_eval results are cached.) However, if  mi_flush_cache is used before the second and every subsequent shader call, the called shader's  mi_eval calls will cause a fresh subshader call.

3.21.1 DB Functions

  Database access functions can be used to convert pointers into tags, and to get the type of a tag. The scene database contains only tags and no pointers at all, because pointers are not valid on other machines. A tag is a 32-bit integer value that uniquely identifies a piece of data in mental ray's  virtual shared database. It acts like a pointer except that it is valid across all machines on the network.

 

    int mi_db_type(
        const miTag tag)

 Return the type of a database item. The tag must exist. Valid types that are of interest in shaders are:


    miSCENE_FUNCTION    Function to call, such as a shading function

    miSCENE_MATERIAL    Material containing shaders and flags
    miSCENE_LIGHT    Light source
    miSCENE_IMAGE    Image in memory

The most important are functions and images, because general-purpose texture shaders need to distinguish procedural and  image textures. See the texture shader example on page [*].

 

    int mi_db_size(
        const miTag tag)

 2.1Return the size of a database item in bytes. The tag must exist. This function should be avoided if possible because it has poor performance and can lead to inefficient execution orders in mental ray 3.0 in certain situations.

 

    void *mi_db_access(
        const miTag tag)

Look up the tag in the database, pin it, and return a pointer to the  referenced item. Pinning means that the database item is guaranteed to stay in memory at the same location until the item is explicitly unpinned. Rendering aborts if the given tag does not exist.  mi_db_access always returns a valid pointer. If an item is accessed twice, it must be unpinned twice; pinned is a counter, not a flag. The maximum number of simultaneous pins on a single database element is 65535.

 

    void mi_db_unpin(
        const miTag tag)

Every tag that was accessed with  mi_db_access must be unpinned  with this function when the pointer is no longer needed. Failure to unpin can cause a pin overflow, which may abort rendering. After unpinning, the pointer may not be used any more.

 

    void mi_db_flush(
        const miTag tag)

 Normally, a shader does not use a pointer obtained with  mi_db_access to write to a database item. If it does, other hosts on the network may still hold stale copies, which must explicitly be deleted by calling this function. This function must be used with great care; it is an error to flush an item that another shader has pinned. For this reason, it is not generally possible to pass information back and forth between shaders or hosts by writing into database items and then flushing them. Geometry shaders are normally the only place where database entries are written, and there are more powerful function libraries available for geometry shaders that do not require  mi_db_flush.

3.21.2 RC Functions

These are the functions supplied by the render modules of mental ray, RC*. All following  trace functions return miTRUE if any subsequent call of a shader returned miTRUE to indicate presence of  illumination. Otherwise no illumination is present and miFALSE is returned.  All trace functions derive the state of the ray to be cast from the given state of the parent ray. This state becomes the `` child state'' that is passed to subsequent shaders that are called by the trace function. The state is always copied, and the given state is not modified except for the state fields label, point, normal, dist and motion. These fields are copied from the child state so that the lens shader can access them in the state modified by  mi_trace_eye. After the trace function returns, the caller may examine the child state (but not the grandchild, which is gone if it ever existed). Volume shaders get the same state as the previous (material) shader. Note that all point and direction vectors passed as arguments to tracing functions must be in  internal space.

 

    miBoolean mi_trace_eye(
        miColor         *result,
        miState         *state,
        miVector        *origin,
        miVector        *direction)

casts an eye ray from origin in direction, or calls the next lens shader. The allowed origin and direction values are restricted when using the  ray classification rendering algorithm (not recommended, it exists only for backwards compatibility). If  scanline rendering is turned on and state- >scanline is not zero, origin and direction must be the same as in the initial call of  mi_trace_eye, and the lens shader may not modify them. Lens shaders that depend on modifying ray origin and direction should be declared with the trace on option. Origin and direction must be given in internal space. This function may be used only in lens shaders. Note that  mi_trace_eye stores origin and direction in state - > org and state - > dir, respectively, overwriting the previous values.

 

    miBoolean mi_trace_reflection(
        miColor         *result,
        miState         *state,
        miVector        *direction)

casts a reflection ray from state- >point to direction. It returns miFALSE if the trace depth has been exhausted. If no intersection is found, the optional environment shader is called. The direction must be given in internal space. This function may be used only in shaders called during image rendering, but not in displacement, geometry, photon, or output shaders.

 

    miBoolean mi_trace_refraction(
        miColor         *result,
        miState         *state,
        miVector        *direction)

casts a refraction ray from state- >point to direction. It returns miFALSE if the  trace depth has been exhausted. If no intersection is found, the optional  environment shader is called. Before this functions casts the refraction ray, after copying the state, it copies state- >refraction_volume to state- >volume because the ray is now assumed to be ``inside'' the object, so the  volume shader that describes the inside should be used to modify the ray while traveling inside the object. It is the caller's responsibility to set state- >refraction_volume to the camera's volume shader state- >camera- >volume or some other volume shader if it determines that the ray is now leaving the object. The direction must be given in internal space.

If ray tracing has been disabled,  mi_trace_refraction cannot modify the ray direction and operates like  mi_trace_transparent. This function may be used only in shaders called during image rendering, but not in displacement, geometry, photon, or output shaders.

 

    miBoolean mi_trace_transparent(
        miColor         *result,
        miState         *state)

does the same as  mi_trace_refraction with dir == state- >dir (that is, no change in the ray direction) but may be executed faster if the parent ray is an eye ray. It also works when ray tracing is turned off. If the ray direction does not change (because no  index of refraction or similar modification is applied), it is more efficient to cast a transparency ray than a refraction ray. Like  mi_trace_refraction, this function copies the refraction  volume shader to the volume shader because the ray is now assumed to be inside the object. This function may be used only in shaders called during image rendering, but not in displacement, geometry, photon, or output shaders.

 

    miBoolean mi_trace_environment(
        miColor         *result,
        miState         *state,
        miVector        *direction)

casts a ray into the environment. The trace depth is not incremented or checked. The  environment shader in the state is called to compute the color to be returned. The direction must be given in internal space.

 

    miBoolean mi_trace_probe(
        miState         *state,
        miVector        *direction,
        miVector        *org)

2.1casts a ray into the scene, starting at org with the direction direction, both in internal space coordinates. If nothing is hit, miFALSE is returned. If the ray hits another object, miTRUE is returned and state - > child is set to the state that the material shader of the hit object would have seen. However, unlike all other mi_trace_* functions, no shader is called. Note that the state state - > child does not itself have a state, so it cannot be used to call a material shader at the hit object directly. This requires setting up an artificial ``grandchild'' state:

          if (mi_trace_probe(state, &dir, &org)) {
                  miState grandchild;
                  state->child->child = &grandchild;
                  if (mi_call_material(&result, state->child))
                          /* use the result */
          }

This sequence works roughly like  mi_trace_reflection, except that no ray levels are tested, no environment is sampled, and no volume shaders are called. Note that  mi_trace_probe will always return miFALSE if ray tracing is disabled.

 

    miBoolean mi_sample_light(
        miColor         *result,
        miVector        *dir,
        miScalar        *dot_nl,
        miState         *state,
        miTag           light_inst,
        miInteger       *samples)

casts a  light ray from the  light source to the intersection point, causing the light source's  light shader to be called. The  light shader may then calculate  shadows by casting a  shadow ray to the intersection point. This may cause  shadow shaders of occluding objects to be called, and will also cause the  volume shader of the state to be called, if there is one. Before the light is sampled, the direction from the current intersection point in the state to the light and the dot product of this direction and the normal in the state are calculated and returned in dir and dot_nl if these pointers are nonzero. The direction is returned in internal space. The light instance to sample must be given in light_inst. samples must point to an integer that is initialized to 0. mi_sample_light must be called in a loop until it returns miFALSE. *samples will then contain the total number of light samples taken; it may be larger than 1 for  area light sources.

For every call in the loop, a different dir and dot_nl is returned because the rays go to different points on the area light source. The caller is expected to use these variables, the returned color, and other variables such as diffuse and specular colors from the shader parameters to compute a color. These colors are accumulated until  mi_sample_light returns miFALSE and the loop terminates. The caller then divides the accumulated color by the number of samples (*samples) if it is greater than 0, effectively averaging all the intermediate results. See page [*] for an example of a shader using  mi_sample_light.

When casting light rays with  mi_sample_light, mental ray may check whether the primitive's normal is pointing away from the light and ignore the light in this case. For this reason some shaders, such as ray-marching volume shaders, should assign 0 to state- >pri first, and restore it before returning. Some  mi_query modes do not work if pri has been modified.

Light instance tags to call this function with can be found either in shader parameters of type light or array light, or in the  global light list obtained from  mi_query.

 

    miBoolean mi_trace_light(
        miColor         *result,
        miVector        *dir,
        miScalar        *dot_nl,
        miState         *state,
        miTag           light_inst)

is a simpler variation of  mi_sample_light that does not keep a sample counter, and is not called in a loop. It is equivalent to  mi_sample_light except for area light sources. Area light sources must be sampled multiple times with different directions, which is not supported accurately by this function because it can only return a single direction and dot_nl. This function is provided for backwards compatibility with mental ray 1.9 only, do not use it for new projects.

 

    miBoolean mi_trace_shadow(
        miColor * const result,
        miState * const state)

computes shadows for the given  light ray by casting  shadow rays. This function is normally called from a  light shader to take occluding objects that prevent some or all of the light emitted by the light source to reach the illuminated point (whose  material shader has probably called the light shader). The result color is modified by the  shadow shaders that are called if occluding objects are found. Note that  light shaders can improve performance by tracing shadow rays only if the contribution from the light is greater than some threshold, for example because distance or angle attenuation has left so little of the light color (less than 1/256, for example) that applying shadow occlusion to this value is not going to make any difference. This function returns miFALSE if full occlusion is detected, that is, result is black.

 

    miBoolean mi_trace_shadow_seg(
        miColor * const result,
        miState * const state)

recursively calls the  shadow shader for the next shadow segment and returns its result, or the result of the  light shader if there is no more shadow intersection. It does nothing if shadow segments are turned off. It is used by shadow shaders only; light shaders always use  mi_trace_shadow. See the introduction to shader types and the shadow shader explanation for details on shadow modes. This function returns miFALSE if full occlusion is detected, that is, result is black.

 

    miBoolean mi_compute_irradiance(
        miColor   *result,
        miState   *state)

 mi_compute_irradiance computes the  irradiance corresponding to indirect diffuse illumination at the intersection point given in state (state - > point). This function is used in  material shaders to add  indirect illumination such as  caustics or  color bleeding2.1. If state - > pri is zero, miFALSE is returned.

 

    miBoolean mi_compute_volume_irradiance(
        miColor   *result,
        miState   *state)

 mi_compute_volume_irradiance computes the  irradiance corresponding to indirect diffuse illumination at the point given in state (state - > point). This function is used in  volume shaders to add  indirect illumination such as multiply scattered light2.1or  volume caustics.

3.21.3 Sampling with mi_sample

 

     miBoolean mi_sample(
         double   *sample,
         int      *instance,
         miState  *state,
         miUshort dimension,
         miUint   *n)

2.1This is mental ray's primary generic sampling function. It can be used to sample arbitrary functions for evaluating integrals by deterministic sample points, which converge faster than their random counterparts and thus reduce rendering time. The  mi_sample function is a high-level easy-to-use interface hiding all mathematical details of advanced quasi-Monte Carlo integration from the shader writer. sample is an array with dimension members that the new sample point will be stored into. Sample results are uniformly distributed in the range [0, 1)dim. instance is the current sample number; it must point to an integer that is initialized to 0 before the first loop iteration. If there is no loop, a null pointer may be passed. state is the current shader state. dimension is the dimension of the sample, such as 3 for XYZ vectors. n must point to an integer that specifies the number of samples to take. If only a single sample is taken, n may be a null pointer. The body of the  mi_sample loop may not write to *sample or *n or vary dimension between any subsequent calls in the same loop because  mi_sample computes the next sample incrementally from the previous.

 mi_sample has three main applications:

1.
generating single samples, which can be used in photon and other shaders for deciding on the kind of physical interaction like glossy, specular, or diffuse scattering, and then selecting a new quasi-random direction. This is the classical case of implementing random walk simulations with the von-Neumann-Ulam scheme.

2.
controlling an adaptive sampling loop, where the number of samples is not known in advance and the sampling loop will be terminated adaptively by the caller. This is the only mode where the caller may and must decide when to break from the loop.

3.
controlling a finite sampling loop. This is the classical case of quasi-Monte Carlo integration, where n samples are drawn and averaged. This can be used for sampling area light sources or depth of field shaders. The advantage of knowning the number of samples n in advance is an increased convergence speed.

Note that the returned sample point sample must be used as one point. This means that several one dimensional samples must not be assembled to yield a multidimensional sample, and that a multidimensional sample must not be used in order to simulate consecutive events. If, for example, 3D sampling vectors are computed with  mi_sample, a single loop with dimension 3 must be used, rather than a higher dimension to obtain other sampling values at the same time, or fewer to compute the X, Y, and Z direction separately. Samples from  mi_sample must be used consecutively. The sequence should not be terminated prematurely, nor should samples be dropped, since rejection sampling will result in biased approximations.

A call to mi_sample in single sample mode looks like:


    void a_single_sample( ... , miState *state,  ... ) 
    {
        double sample[2];
        
        mi_sample(sample, 0, state, 2, 0);
        /* use sample[0] and sample[1] */
    }

The sampling dimension in this example is 2. Since only a single sample is required, no sample counting is indicated by passing a null pointer as *instance counter and to the required number of samples n. After the call to mi_sample, the array x holds a two-dimensional sample point of [0, 1)2. The function call always returns miFALSE in single sample mode.

In the adaptive sampling mode, the number of samples to be taken is not known in advance, and the code must decide when to break from the loop (which it may not in the other two modes, where  mi_sample returns miFALSE).  mi_sample is then used the following way:


    void adaptive_sampling( ... , miState *state,  ... )

    {
        double sample[5];
        int sample_number = 0;
        
        while (mi_sample(sample, &sample_number, state, 5, 0)) {
            /* use sample[0], ..., sample[4] */
            if (enough samples taken)
                break;
        }
    }

Adaptive sampling is indicated to  mi_sample by passing a null pointer as the number of samples n. The while loop is then controlled by the  mi_sample call, which always returns miTRUE in adaptive sampling mode. The current sample number starting with 1 for the first sample is kept in sample_number. This variable must be initialized to zero in order to force initialization in  mi_sample. Note that in deterministic sampling, adaptive sampling (here, the break condition) cannot be controlled by the calculation of variance as in Monte Carlo context. This will result in biased approximations. Adaptive sampling here could be based on contrast calculations, for example. sample holds a sample point in the five-dimensional unit cube [0, 1)5.

In the classical case, where the number of samples is known in advance, the deterministic sampling controlled by  mi_sample very much resembles a Monte Carlo quadrature:


    void finite_sampling( ... , miState *state,  ... )

    {
        const miUint samples = 16;
        double sample[2];
        int sample_number = 0;
        
        while (mi_sample(sample, &sample_number, state, 2, &samples)) {
            /* use sample[0], sample[1] */
        }
    }

Here, all arguments of mi_sample are used. Unlike the previous adaptive sampling case, the number of samples is passed explicitly to  mi_sample. Again the integer variable sample_number is initialized to zero and passed by reference to instance. *state is the current state of the shader.  mi_sample returns miTRUE for samples iterations of the loop, until finally miFALSE is returned to terminate the loop. The loop should not be terminated with a break or return statement, because then the internal state of state does not guarantee convergence of rendering any longer (that is, state - > qmc_instance and state - > qmc_component are wrong until the shader terminates). In the loop, *instance provides the current sample number, starting at 1, until samples is reached. The loop controls a two-dimensional integration, where sample is an array of doubles with two elements. The vector sample is the sample point in the two-dimensional unit cube [0, 1)2. The finite sampling mode exposes a faster convergence than the adaptive sampling mode. Exceptional convergence can be achieved if the number of samples is

samples = $\displaystyle \prod_{i = 1}^{{\it dimension} - 1}$piki,

where pi are the prime numbers, i.e. p1 = 2, p2 = 3, etc., and ki $ \in$  *0.1exI   N is a (positive) natural number. In two dimensions, i.e. dimension == 2, samples should be a power of 2. In the special case of dimension == 1, any number of samples can be used in order to achieve optimal convergence.

3.21.4 RC Photon Functions

The functions in this section implement photon tracing. They are to be used in  photon shaders. If  caustics or  global illumination2.1are enabled, rendering distinguishes two phases:  photon tracing and  scanline rendering/ ray tracing. Photon tracing is done first. It sends  photons from certain  light sources into the scene. When a photon hits an object, the object's  photon shader is called, which then gets the opportunity to absorb the photon or use one of the mi_photon_* functions to let the photon continue. The photon functions can be used only in photon shaders. Photon shaders may not use regular ray tracing functions such as  mi_trace_reflection.

         There are three main categories of photon tracing: specular, glossy, and diffuse. These terms define the distribution of the secondary photons in terms of the amount of scattering. Polished surfaces like chrome or clear glass are specular; unpolished surfaces such as aluminum or lightly frosted glass are glossy, and surfaces with no directional reflection or refraction such as paper are diffuse.

Photon tracing and  ray tracing are similar in many respects, and use similar function calls. Although the operation underneath is quite different (tracing photons vs. tracing rays), a table of the operations in each phase shows the similarity as far as the shaders are concerned:

photons rays
emanate from light sources emanate from the camera
call photon material shaders call material shaders
call photon volume shaders call volume shaders
call photon emission shaders call light shaders
-- call lens shaders
-- call environment shaders
  mi_photon_light   mi_trace_eye
  mi_reflection_dir_specular   mi_reflection_dir
  mi_reflection_dir_glossy --
  mi_reflection_dir_anisglossy --
  mi_reflection_dir_diffuse --
  mi_transmission_dir_specular   mi_refraction_dir
  mi_transmission_dir_glossy --
  mi_transmission_dir_anisglossy --
  mi_transmission_dir_diffuse --
  mi_scattering_dir_diffuse --
  mi_scattering_dir_directional --
  mi_scattering_pathlength --
  mi_photon_reflection_specular   mi_trace_reflection
  mi_photon_reflection_glossy2.1 --
  mi_photon_reflection_diffuse2.1 --
  mi_photon_transmission_specular   mi_trace_refraction
  mi_photon_transmission_glossy2.1 --
  mi_photon_transmission_diffuse2.1 --
  mi_photon_transparent   mi_trace_transparent
  mi_photon_volume_scattering --
  mi_store_photon   mi_compute_irradiance
  mi_store_volume_photon   mi_compute_volume_irradiance

There are three mi_photon_reflection_* functions and three mi_photon_refraction_* functions (as well as a function for transparency and one for volume scattering). Why not just one reflection function and one transmission function, similar to  mi_trace_reflection and  mi_trace_refraction?

The reason is that mental ray needs to know what type of reflections and transmissions the photon has undergone (its ``path history'') to determine which photon map to store it in, when not to store the photon, and when to terminate the photon path.

The photon reflection and transmission functions all follow the same pattern: first they check whether the intersected object is a caustic generator, if tracing caustic photons. If the object is not a caustic generator, the photon is not traced further and miFALSE is returned. A similar check is made for  global illumination generating objects if tracing global illumination photons. Then a new state is set up with the appropriate ray type, reflection and refraction level, origin and direction (and the volume in the transmission case).

Photon shaders,  photon volume shaders, and  photon emission shaders are optional; if one is missing mental ray uses built-in defaults. The default photon shader absorbs all photons, the default photon volume shader behaves like empty space, and the default photon emission shader behaves like a point  light source emitting photons uniformly in all directions (that have a chance of contributing illumination -- but this is only an optimization).

 Photon shaders can use the function  mi_choose_scatter_type to select which type of reflection or transmission the photon should undergo next.  mi_choose_scatter_type chooses a scatter type (reflection or transmission, diffuse, glossy, or specular) or absorption. The choice is made with probabilities depending on the scattering coefficients and the transparency. The scattering type with the highest scattering coefficients has the highest probability.

In the following, d denotes diffuse, g denotes glossy, and s denotes specular, and the indices r, g, and b mean red, green, and blue, respectively. Each of the nine scattering coefficients (specular R, G, B, glossy R, G, B, diffuse R, G, B) and the transparency must be in the range [0...1]. Furthermore, the scattering coefficients must satisfy the following conditions:

dr + gr + sr$\displaystyle \le$1      
dg + gg + sg$\displaystyle \le$1      
db + gb + sb$\displaystyle \le$1      

If these conditions are not met, the coefficients are adjusted so that they are met, and a warning is given (once). The probability for scattering (that is, choosing one of the six types of reflection or transmission) is

P = max(dr + gr + srdg + gg + sgdb + gb + sb).

The probability for absorption is

1 - P.

The probability for diffuse reflection2.1 is

P . (1 - t) . $\displaystyle {{d_r+d_g+d_b} \over
{d_r+d_g+d_b+g_r+g_g+g_b+s_r+s_g+s_b}}$

while the probability for diffuse transmission2.1 is

P . t . $\displaystyle {{d_r+d_g+d_b} \over
{d_r+d_g+d_b+g_r+g_g+g_b+s_r+s_g+s_b}}$.

Similar for glossy and specular reflection and transmission. If a certain scattering type is chosen, the three scattering coefficients (r, g, b) for that type of scattering are adjusted following the ``Russian roulette'' method. Note that glossy and diffuse scattering2.1 will not be chosen if  caustics are being simulated -- only specular scattering (or absorption) is possible then.

The connection between the  photon tracing and  ray tracing phases is the  mi_compute_irradiance function. It allows  material shaders (during image rendering) to get the  caustic or  global illumination2.1color using the photons that were stored in the photon tracing phase. The function  mi_compute_volume_irradiance is similar, but computes irradiance in a volume using the photons stored in the volume.

This distinction is still valid if  ray tracing is disabled and mental ray is reduced to  scanline rendering in the second phase. For the purposes of  photon tracing, scanline rendering can be considered a ``ray tracing emulation'' mode that achieves similar effects but never actually traces a ray, at the cost of not being able to control the ray direction. For example, if the trace off statement or -trace off command-line option is specified, it is still possible to generate a  caustic, but the second phase will be unable to compute raytraced reflections and refractions.

 

    void mi_photon_light(
        miColor         *energy,
        miState         *state)

traces a  photon from a  light source into the scene. The photon origin is state - > org and the direction is state - > dir. This function should be used only in photon emitting shaders.

 

    miBoolean mi_photon_reflection_specular(
        miColor         *energy,
        miState         *state,
        miVector        *direction)

traces a specularly reflected photon with energy in direction direction. This function may be used only in  photon shaders.

 

    miBoolean mi_photon_reflection_glossy(
        miColor         *energy,
        miState         *state,
        miVector        *direction)

2.1traces a glossily reflected photon with energy in direction direction. This function may be used only in  photon shaders.

 

    miBoolean mi_photon_reflection_diffuse(
        miColor         *energy,
        miState         *state,
        miVector        *direction)

2.1traces a diffusely reflected photon with energy in direction direction. This function may be used only in  photon shaders.

 

    miBoolean mi_photon_transmission_specular(
        miColor         *energy,
        miState         *state,
        miVector        *direction)

traces a specularly transmitted photon with energy in direction direction. This function may be used only in  photon shaders.

 

    miBoolean mi_photon_transmission_glossy(
        miColor         *energy,
        miState         *state,
        miVector        *direction)

2.1traces a glossily transmitted photon with energy in direction direction. This function may be used only in  photon shaders.

 

    miBoolean mi_photon_transmission_diffuse(
        miColor         *energy,
        miState         *state,
        miVector        *direction)

2.1traces a diffusely transmitted photon with energy in direction direction. This function may be used only in  photon shaders.

 

    miBoolean mi_photon_transparent(
        miColor         *energy,
        miState         *state)

traces a specularly transmitted photon with energy in the direction indicated by the state (the same direction as the previous direction). This function may be used only in  photon shaders.

 

    miBoolean mi_photon_volume_scattering(
        miColor         *energy,
        miState         *state,
        miVector        *dir);

traces a photon, scattered by a volume, with energy in direction direction. This function may be used only in  photon shaders.

 

    void mi_store_photon(
        miColor         *energy,
        miState         *state)

 mi_store_photon stores a  photon with the given energy in the  photon map at the intersection point given in state state - > point). Only photons with non-zero energy are stored. Photons should only be stored at surfaces which have a diffuse component in order to limit the storage costs and reduce the rendering time. This function may be used only in  photon shaders.

 

    void mi_store_volume_photon(
        miColor         *energy,
        miState         *state)

This function is equivalent to the previous, except that it is used to store a photon in a volume instead of on a surface. It is used for volume caustics and volume scattering (such as volumic light beams and clouds).

3.21.5 RC Direction Functions

The functions in this section compute ray or photon directions. In both photon and ray tracing, shaders normally first compute a direction for secondary photons or rays using one of the functions with _dir in the name, and then call the corresponding photon or ray tracing function with the resulting direction.

The functions  mi_choose_scatter_type, mi_reflection_dir_*, mi_transmission_dir_*, and mi_scattering_dir_* can also be used in other contexts than photon tracing, but they are listed in the photon tracing column above because they are most often used for that purpose. However, the glossy direction functions, for example, can just as well be used for ray tracing if the rendering quality setting (contrast and sampling limits) are high enough to avoid noisy images. Using diffuse directions for ray tracing is unlikely to produce acceptable results due to noise.

 

    void mi_reflection_dir(
        miVector        *dir,
        miState         *state);

Calculate the reflection direction based on the dir, normal, and normal_geom state variables. The returned direction dir can be passed to  mi_trace_reflect. It is returned in  internal space.

 

    void mi_reflection_dir_specular(
        miVector        *dir,
        miState         *state);

Same as  mi_reflection_dir: computes the mirror direction. Created for symmetry with the similar functions for glossy and diffuse reflection.

 

    void mi_reflection_dir_glossy(
        miVector        *dir,
        miState         *state,
        miScalar        shiny);

Choose a direction near the direction of ideal specular reflection (mirror direction). If shiny is low (for example 5), a wide distribution of directions results; if shiny is high (for example 100), a narrow distribution results.

 

    void mi_reflection_dir_anisglossy(
        miVector        *dir,
        miState         *state,
        miVector        *u,
        miVector        *v,
        miScalar        shiny_u,
        miScalar        shiny_v);

Like  mi_reflection_dir_glossy, but with different shinynesses in different directions. The u and v vectors specify the local surface orientation.

 

    void mi_reflection_dir_diffuse(
        miVector        *dir,
        miState         *state)

Choose a direction with a distribution according to Lambert's cosine law for  diffuse reflection.

 

    miBoolean mi_refraction_dir(
        miVector        *dir,
        miState         *state,
        miScalar        ior_in,
        miScalar        ior_out);

Calculate the refraction direction in  internal space based on the interior and exterior indices of refraction ior_in and ior_out, and on dir, normal, and normal_geom state variables. The returned direction dir can be passed to  mi_trace_refract. Returns miFALSE and leaves *dir undefined in case of total internal reflection.

 

    miBoolean mi_transmission_dir_specular(
        miVector        *dir,
        miState         *state,
        miScalar        ior_in,
        miScalar        ior_out);

Same as  mi_refraction_dir, since specular transmission occurs in the refraction direction. Created for symmetry with the similar functions for glossy and diffuse transmission.

 

    miBoolean mi_transmission_dir_glossy(
        miVector        *dir,
        miState         *state,
        miScalar        ior_in,
        miScalar        ior_out,
        miScalar        shiny);

Choose a direction near the direction of ideal specular transmission (the refraction direction). If shiny is low, a very wide distribution of directions results; if shiny is high a narrow distribution results.

 

    miBoolean mi_transmission_dir_anisglossy(
        miVector  *dir,
        miState   *state,
        miScalar  ior_in,
        miScalar  ior_out,
        miVector  *u,
        miVector  *v,
        miScalar  shiny_u,
        miScalar  shiny_v);

Choose a direction for anisotropic glossy transmission. The u and v vectors specify the local surface orientation.

 

    void mi_transmission_dir_diffuse(
        miVector        *dir,
        miState         *state)

Choose a direction with a distribution according to Lambert's cosine law for diffuse transmission (also known as ``diffuse  translucency'').

 

    void mi_scattering_dir_diffuse(
        miVector        *dir,
        miState         *state)

Choose a direction with a uniform probability over the whole sphere. This is useful for  volume scattering.

 

    void mi_scattering_dir_directional(
        miVector        *dir,
        miState         *state
        miScalar        directionality)

Choose a direction with a probability determined by directionality. For values between -1 and 0 it models volume  backscattering (with -1 being the most directional), for a value of 0 it models diffuse (isotropic)  volume scattering, and for values between 0 and 1 it models  forward volume scattering.

 

    miScalar mi_scattering_pathlength(
        miState  *state,
        miScalar k);

Based on probability and exponential falloff, select a path length for a photon in a participating medium2.1with density k.

3.21.6 IMG Functions

The IMG module of mental ray provides functions that deal with images. There are functions to read and write  image files in various formats, and to access in-core  frame buffers such as image  textures. First, the functions that access  frame buffers are listed. These functions are typically used by  texture shaders, which can obtain an image pointer by calling mi_db_access with the image tag as an argument. All these functions do nothing or return defaults if the image pointer is 0, or if the x or ycoordinate is out of bounds. They do not check whether the frame buffer has the correct data type. All these functions are available in all shaders, including displacement, geometry, and output shaders.

 

    void mi_img_put_color(
        miImg_image *image,
        miColor     *color,
        int         x,
        int         y)

Store the color color in the color frame buffer image at coordinate x y, after performing  desaturation or  color clipping,  gamma correction, compensating for  premultiplication, and  dithering. Not all of these steps may be performed, and the behavior is dependent on the options colorclip2.1, premultiply, desaturate, gamma, and dither as given on the command line or in the .mi file. This function works with 1, 2, or 4 components per pixel, and with 8, 16, or 32 (float) bits per component. The normal range for the R, G, B, and A color components is [0, 1] inclusive. For 32 bit (float) frame buffers only compensation for premultiplication is done.

 

    void mi_img_get_color(
        miImg_image *image,
        miColor     *color,
        int         x,
        int         y)

This is the reverse function to  mi_img_put_color. It returns the color stored in a frame buffer at the specified coordinates. Gamma compensation and premultiplication, if enabled by  mi_img_mode, are applied in reverse. The returned color may differ from the original color given to  mi_img_put_color because of color clipping and  color quantization.

 

    void mi_img_put_scalar (
        miImg_image *image,
        float       scalar,
        int         x,
        int         y)

Store the scalar scalar in the scalar frame buffer image at coordinate x y, after clipping to the range [0, 1]. Scalars are stored as 8-bit or 16-bit unsigned values. This function is intended for scalar texture files of type miIMG_S or miIMG_S_16.

 

    void mi_img_get_scalar (
        miImg_image *image,
        float       *scalar,
        int         x,
        int         y)

This is the reverse function to  mi_img_put_scalar. It returns the scalar stored in a frame buffer at the specified coordinates, converted to a scalar in the range [0, 1]. If the frame buffer pointer is 0, or if the x or y coordinate is out of bounds, the scalar is set to 0.

 

    void mi_img_put_vector (
        miImg_image *image,
        miVector    *vector,
        int         x,
        int         y)

Store the X and Y components of the vector vector in the vector frame buffer image at coordinate x y, after clipping to the range [- 1, 1]. Vectors are stored as 16-bit signed values. This function is intended for vector texture files of type miIMG_VTA or miIMG_VTS.

 

    void mi_img_get_vector (
        miImg_image *image,
        miVector    *vector,
        int         x,
        int         y)

This is the reverse function to  mi_img_put_vector. It returns the UV vector stored in a frame buffer at the specified coordinates, with coordinates converted to the range [- 1, 1]. The Z component of the vector is always set to 0. If the frame buffer pointer is 0, or if the x or y coordinate is out of bounds, all components are set to 0.

 

    void mi_img_put_depth(
        miImg_image *image,
        float       depth,
        int         x,
        int         y)

Store the depth value depth in the frame buffer image at the coordinates x y. The depth value is not changed in any way. The standard interpretation of the depth is the (positive) Z distance of objects relative to the camera. mental ray uses this function internally to store - state - > point.z (in camera space) if the depth frame buffer is enabled with an appropriate output statement. By convention, the value 0.0 signifies infinite distance.

 

    void mi_img_get_depth(
        miImg_image *image,
        float       *depth,
        int         x,
        int         y)

Read the depth value to the float pointed to by depth from frame buffer image at the coordinates x y. If the image pointer is 0, or if the x or y coordinate is out of bounds, return the MAX_FLT constant from limits.h.

 

    void mi_img_put_normal(
        miImg_image *image,
        miVector    *normal,
        int         x,
        int         y)

Store the  normal vector normal in the frame buffer image at the coordinates x y. The normal vector is not changed in any way. This function can also be used for the motion vector frame buffer.

 

    void mi_img_get_normal(
        miImg_image *image,
        miVector    *normal,
        int         x,
        int         y)

Read the normal vector normal from frame buffer image at the coordinates x y. If the image pointer is 0, or if the x or ycoordinate is out of bounds, return a null vector. This function can also be used for the  motion vector  frame buffer.

 

    void mi_img_put_label(
        miImg_image *image,
        miUint      label,
        int         x,
        int         y)

Store the  label value label in the  label frame buffer image at the coordinates x y. The label value is not changed in any way.

 

    void mi_img_get_label(
        miImg_image *image,
        miUint      *label,
        int         x,
        int         y)

Read the label value to the unsigned integer pointed to by label from frame buffer image at the coordinates x y. If the image pointer is 0, or if the x or y coordinate is out of bounds, return 0.

3.21.7 Math Functions

 Math functions include common vector and matrix operations. More specific noise and rendering functions can be found in the next two sections, Noise Functions and Auxiliary Functions.

  

    void mi_vector_neg(
        miVector    *r)

r : = - r

 

    void mi_vector_add(
        miVector    *r,
        miVector    *a,
        miVector    *b)

r : = a + b

 

    void mi_vector_sub(
        miVector    *r,
        miVector    *a,
        miVector    *b)

r : = a - b

 

    void mi_vector_mul(
        miVector    *r,
        miScalar    f)

r : = r . f

 

    void mi_vector_div(
        miVector    *r,
        miScalar    f)

r : = r . $ {1 \over f}$        (If f is zero, leave r unchanged.)

 

    void mi_vector_prod(
        miVector    *r,
        miVector    *a,
        miVector    *b)

r : = a x b

 

    miScalar mi_vector_dot(
        miVector    *a,
        miVector    *b)

a . b

 

    miScalar mi_vector_norm(
        miVector    *a)

$ \Vert$a$ \Vert$

 

    void mi_vector_normalize(
        miVector    *r)

r : = $ {r \over{\Vert r \Vert}}$        (If r is a null vector, leave r unchanged.)

 

    void mi_vector_min(
        miVector    *r,
        miVector    *a,
        miVector    *b)

r : = $ \left(\vphantom{ \begin{array}{ccccc}
a_x < b_x &\mbox{?}& a_x &\mbox{:}& b_x\...
...y &\mbox{:}& b_y\\
a_z < b_z &\mbox{?}& a_z &\mbox{:}& b_z
\end{array}}\right.$$ \begin{array}{ccccc}
a_x < b_x &\mbox{?}& a_x &\mbox{:}& b_x\\
a_y < b_y &\mbox{?}& a_y &\mbox{:}& b_y\\
a_z < b_z &\mbox{?}& a_z &\mbox{:}& b_z
\end{array}$ $ \left.\vphantom{ \begin{array}{ccccc}
a_x < b_x &\mbox{?}& a_x &\mbox{:}& b_x\...
...y &\mbox{:}& b_y\\
a_z < b_z &\mbox{?}& a_z &\mbox{:}& b_z
\end{array}}\right)$


 

    void mi_vector_max(
        miVector    *r,
        miVector    *a,
        miVector    *b)

r : = $ \left(\vphantom{ \begin{array}{ccccc}
a_x > b_x &?& a_x &:& b_x\\
a_y > b_y &?& a_y &:& b_y\\
a_z > b_z &?& a_z &:& b_z
\end{array}}\right.$$ \begin{array}{ccccc}
a_x > b_x &?& a_x &:& b_x\\
a_y > b_y &?& a_y &:& b_y\\
a_z > b_z &?& a_z &:& b_z
\end{array}$ $ \left.\vphantom{ \begin{array}{ccccc}
a_x > b_x &?& a_x &:& b_x\\
a_y > b_y &?& a_y &:& b_y\\
a_z > b_z &?& a_z &:& b_z
\end{array}}\right)$


 

    miScalar mi_vector_det(
        miVector    *a,
        miVector    *b,
        miVector    *c)

$ \left\vert\vphantom{
\begin{array}{ccc}
a_x & b_x & c_x\\
a_y & b_y & c_y\\
a_z & b_z & c_z
\end{array}}\right.$$ \begin{array}{ccc}
a_x & b_x & c_x\\
a_y & b_y & c_y\\
a_z & b_z & c_z
\end{array}$ $ \left.\vphantom{
\begin{array}{ccc}
a_x & b_x & c_x\\
a_y & b_y & c_y\\
a_z & b_z & c_z
\end{array}}\right\vert$


 

    miScalar mi_vector_dist(
        miVector    *a,
        miVector    *b)

$ \Vert$a - b$ \Vert$


  

    void mi_matrix_null(
        miMatrix     r)

R : = $ \left(\vphantom{
\begin{array}{cccc}
{\tt0} & {\tt0} & {\tt0} & {\tt0}\\
{\tt...
...tt0} & {\tt0} & {\tt0}\\
{\tt0} & {\tt0} & {\tt0} & {\tt0}
\end{array}}\right.$$ \begin{array}{cccc}
{\tt0} & {\tt0} & {\tt0} & {\tt0}\\
{\tt0} & {\tt0} & {\t...
...t0} & {\tt0} & {\tt0} & {\tt0}\\
{\tt0} & {\tt0} & {\tt0} & {\tt0}
\end{array}$ $ \left.\vphantom{
\begin{array}{cccc}
{\tt0} & {\tt0} & {\tt0} & {\tt0}\\
{\tt...
...tt0} & {\tt0} & {\tt0}\\
{\tt0} & {\tt0} & {\tt0} & {\tt0}
\end{array}}\right)$


 

    void mi_matrix_ident(
        miMatrix     r)

R : = $ \left(\vphantom{
\begin{array}{cccc}
{\tt 1} & {\tt0} & {\tt0} & {\tt0}\\
{\t...
...0} & {\tt 1} & {\tt0}\\
{\tt0} & {\tt0} & {\tt0} & {\tt 1}
\end{array}}\right.$$ \begin{array}{cccc}
{\tt 1} & {\tt0} & {\tt0} & {\tt0}\\
{\tt0} & {\tt 1} & {...
...} & {\tt0} & {\tt 1} & {\tt0}\\
{\tt0} & {\tt0} & {\tt0} & {\tt 1}
\end{array}$ $ \left.\vphantom{
\begin{array}{cccc}
{\tt 1} & {\tt0} & {\tt0} & {\tt0}\\
{\t...
...0} & {\tt 1} & {\tt0}\\
{\tt0} & {\tt0} & {\tt0} & {\tt 1}
\end{array}}\right)$


 

    miBoolean mi_matrix_isident(
        miMatrix     a)

Return miTRUE if a is the identity matrix, and miFALSE otherwise.


  

    void mi_matrix_copy(
        miMatrix     r,
        miMatrix     a)

R : = A


 

    miBoolean mi_matrix_invert(
        miMatrix     r,
        miMatrix     a)

R : = A-1        (Returns miFALSE if the matrix cannot be inverted.)

 

    void mi_matrix_prod(
        miMatrix     r,
        miMatrix     a,
        miMatrix     b)

R : = A x B

 

    void mi_matrix_rotate(
        miMatrix        a,
        const miScalar  xrot,
        const miScalar  yrot,
        const miScalar  zrot)

Create a rotation matrix a rotating by xrot, then yrot, then zrot, in radians.

 

    void mi_matrix_rotate_axis(
        miMatrix        a,
        miVector const  *v,
        miScalar const  r)

This function is similar to the previous, except that the rotation is specified with an axis and an angle. The resulting matrix will rotate a point r radians about the axis v according to the right-hand rule. v must have unit length, otherwise the result is undefined.

All the following transformation functions may be called with identical pointers r and v. The vector is transformed in-place in this case. If the matrix m is a null pointer, no transformation is done and v is copied to r. If the result of a transformation is a point in  homogeneous coordinates with a wcomponent that is not equal to 1.0, the result vector's x, y, and z components are divided by w. For  point transformations, a w component of 1.0 is implicitly appended to the v vector at the vector-matrix multiplication. For  vector transformations the wcomponent is implicitly zero. Note the distinction between object and light transformations -- both sets deal with object space, but the former uses the current object's object space and the latter uses the current light's object space.

 

    float mi_matrix_rot_det(
        miMatrix        a)

Return the determinant of the 3 x 3 rotation part of matrix a.

 

    void mi_point_transform(
        miVector    *r,
        miVector    *v,
        miMatrix     m)

r : = v . M

 

    void mi_vector_transform(
        miVector    *r,
        miVector    *v,
        miMatrix     m)

r : = v . M        Only the upper left 3-by-3 submatrix is used since this is a vector transform. The translation row in the matrix is ignored as w is implicitly assumed to be 0.

 

    void mi_vector_transform_T(
        miVector    *r,
        miVector    *v,
        miMatrix     m)

r : = v . MT        The transpose of the upper left 3-by-3 submatrix is used for the vector transformation. The w component of v is implicitly assumed to be 0. This function is required for transformation of normals.

 

    void mi_point_to_world(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert internal point v in the state to  world space, r.

 

    void mi_point_to_camera(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert internal point v in the state to  camera space, r.

 

    void mi_point_to_object(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert internal point v to the  object space of the current object (illuminated point), r.

 

    void mi_point_to_light(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

2.1Convert internal point v in the state to the  object space of the current light. This function (and the other five light transformation functions described below) are similar to the corresponding object transformation functions except that they use state - > light_instance instead of state - > instance to locate the correct object space transformation matrices.

 

    void mi_point_to_raster(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert internal point v in the state to 2D  raster space, r. Raster space dimension is defined by the camera resolution.

 

    void mi_point_from_world(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert point v in  world space to  internal space, r.

 

    void mi_point_from_camera(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert point in  camera space v to  internal space, r.

 

    void mi_point_from_object(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert point v in the  object space of the current object (illuminated point) to  internal space, r.

 

    void mi_point_from_light(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

2.1Convert point v in the  object space of the current light as found in state - > light_instance to  internal space, r.

 

    void mi_vector_to_world(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert internal vector v in the state to  world space, r. Vector transformations work like point transformations, except that the translation row of the transformation matrix is ignored. The resulting vector is not renormalized. Vector transformations transform normals correctly only if there is no scaling. For correct transformation of normals use the normal transformations described below.

 

    void mi_vector_to_camera(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert internal vector v in the state to  camera space, r.

 

    void mi_vector_to_object(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert internal vector v to the  object space of the current object (illuminated point), r.

 

    void mi_vector_to_light(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

2.1Convert internal vector v in the state to  object space of the current light as found in state - > light_instance, r.

 

    void mi_vector_from_world(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert vector v in  world space to  internal space, r.

 

    void mi_vector_from_camera(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert vector in  camera space v to  internal space, r.

 

    void mi_vector_from_object(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert vector v in the  object space of the current object (illuminated point) to  internal space, r.

 

    void mi_vector_from_light(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

2.1Convert vector v in  object space of the current light as found in state - > light_instance to  internal space, r.

 

    void mi_normal_to_world(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert internal normal v in the state to  world space, r. Normal transformations work like  vector transformations, except that the transpose of the inverse transformation matrix used. The resulting vector is not renormalized. This ensures that if a vector and a normal are orthogonal in one coordinate system they remain orthogonal after they have been transformed to a different coordinate system. This holds for arbitrary, not necessarily orthogonal transformations. The vector transformations described above transform normals correctly only if there is no scaling.

 

    void mi_normal_to_camera(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert internal normal v in the state to  camera space, r.

 

    void mi_normal_to_object(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert internal normal v to the  object space of the current object (illuminated point), r.

 

    void mi_normal_to_light(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

2.1Convert internal normal v in the state to  object space of the current light as found in state - > light_instance, r.

 

    void mi_normal_from_world(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert normal v in  world space to  internal space, r.

 

    void mi_normal_from_camera(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert normal in  camera space v to  internal space, r.

 

    void mi_normal_from_object(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

Convert normal v in the  object space of the current object (illuminated point) to  internal space, r.

 

    void mi_normal_from_light(
        miState  * const  state,
        miVector * const  r,
        miVector * const  v)

2.1Convert normal v in  object space of the current light as found in state - > light_instance to  internal space, r.

3.21.8 Noise Functions

The functions in this group provide pseudo-random numbers, quasi-Monte Carlo numbers (using low-discrepancy sequences that converge faster than pseudo-random numbers), and deterministic Perlin noise.

 

    miScalar mi_random(void)

Return a  random number in the range [0, 1). This is similar to drand48 in the standard Unix libraries, but it is available on all platforms including Windows NT, which does not support drand48.

 

    miScalar mi_srandom(
        long            seed)

Begin a new random number sequence for  mi_random. This is equivalent to the standard Unix library function srand48.

 

    miScalar mi_erandom(
        unsigned short  seed[3])

Return a  random number in the range [0, 1), based on the given seed. This allows shaders to create private random number generators by initializing a private seed array to some arbitrary but constant values, and passing it to  mi_erandom without the chance of other functions or threads disturbing the sequence by ``stealing'' random numbers (assuming they do not have access to the private seed). This is equivalent to the standard Unix library function erand48.

 

    miScalar mi_par_random(
        miState         *state)

Return a parallel-safe random number in the range [0, 1). Parallel-safe random numbers can be used in parallel rendering to produce consistent results that do not change when the number of machines or threads changes, or when the execution order changes. All shaders that use this function share the same internal seed value. This function should not be used in geometry shaders, displacement shaders, photon shaders, output shaders, or _init functions of shaders because the initial seed of the random number sequence is undefined in these cases.

 

    miScalar mi_spline(
        miScalar         t,
        const int        n,
        miScalar * const ctl)

This function calculates a one-dimensional  cardinal spline at location t. The t parameter must be in the range 0...1. The spline is defined by n control points specified in the array ctl. There must be at least two control points. To calculate multi-dimensional splines, this function must be called once for each dimension. For example, spline can be used three times to interpolate colors smoothly.

  

    miScalar mi_noise_1d(
        const miScalar   p)

Return a one-dimensional  coherent noise function of p. All six noise functions compute a modified  Perlin noise function from the given one, two, or three dimension parameters such that the noise changes gradually with changing parameters. The modification of the classical algorithm avoids large-scale periodical behavior at lattice points, such that the noise is smooth on all levels. (This makes the algorithm perform slower than classical Perlin noise.) The returned values are in the range 0...1, with a bell-shaped distribution centered at 0.5 and falling off to both sides. This means that 0.5 is returned most often, and values of less than 0.0 and more than 1.0 are never returned. See [Perlin 85].

 

    miScalar mi_noise_2d(
        const miScalar   u,
        const miScalar   v)

Return a two-dimensional noise function of u, v.

 

    miScalar mi_noise_3d(
        miVector * const p)

Return a three-dimensional noise function of the vector p. This is probably the most useful noise function; a simple procedural texture shader can be written that converts a copy of the state- >point vector to  object space, passes it to mi_noise_3d, and assigns the returned value to the red, green, and blue components of the result color. The average feature size of the texture will be approximately one unit in space.

 

    miScalar mi_noise_1d_grad(
        const miScalar   p,
        miScalar * const g)

Return a one-dimensional noise function of p. The gradient of the computed texture at the location p is assigned to *g. Gradients are not normalized.

 

    miScalar mi_noise_2d_grad(
        const miScalar    u,
        const miScalar    v,
        miScalar * const gu,
        miScalar * const gv)

Return a two-dimensional noise function of u, v. The gradient is assigned to *gu and *gv.

 

    miScalar mi_noise_3d_grad(
        miVector * const p,
        miVector * const g)

Return a three-dimensional noise function of the vector p. The gradient is assigned to the vector g.

      

    miScalar mi_unoise_1d()
    miScalar mi_unoise_2d()
    miScalar mi_unoise_3d()
    miScalar mi_unoise_1d_grad()
    miScalar mi_unoise_2d_grad()
    miScalar mi_unoise_3d_grad()

These functions are similar to the regular noise functions, except that the returned distribution is uniform. All returned values are roughly equally likely.

3.21.9 Auxiliary Functions

The following functions are provided for support of shaders, to simplify common mathematical operations required in shaders:

 

    miScalar mi_fresnel(
        miScalar        ior_in,
        miScalar        ior_out,
        miScalar        factor1,
        miScalar        factor2);

Compute the reflected intensity according to  Fresnel:

$\displaystyle {1\over 2}$$\displaystyle \Bigl($$\displaystyle {{{i_{in} \cdot f_2} - {i_{out} \cdot f_1}} \over
{{i_{in} \cdot f_2} + {i_{out} \cdot f_1}}}$$\displaystyle \Bigr)^{2}_{}$ + $\displaystyle \Bigl($$\displaystyle {{{i_{in} \cdot f_1} - {i_{out} \cdot f_2}} \over
{{i_{in} \cdot f_1} + {i_{out} \cdot f_2}}}$$\displaystyle \Bigr)^{2}_{}$

 

    miScalar mi_fresnel_reflection(
        miState         *state,
        miScalar        ior_in,
        miScalar        ior_out);

Call  mi_fresnel with parameters appropriate for the given indices of refraction ior_in and ior_out, and for the dot_nd state variable.

 

    miScalar mi_phong_specular(
        miScalar        spec_exp,
        miState         *state,
        miVector        *dir);

Calculate the Phong factor based on the direction of illumination dir, the specular exponent spec_exp, and the state variables normal and dir. The direction must be given in  internal space.

 

    void mi_fresnel_specular(
        miScalar        *ns,
        miScalar        *ks,
        miScalar        spec_exp,
        miState         *state,
        miVector        *dir,
        miScalar        ior_in,
        miScalar        iot_out);

Calculate the specular factor ns based on the illumination direction dir, the specular exponent spec_exp, the inside and outside indices of refraction ior_in and ior_out, and the state variables normal and dir. ks is the value returned by  mi_fresnel, which is called by  mi_fresnel_specular. The direction must be given in  internal space.

 

    miBoolean mi_cooktorr_specular(
        miColor         *result,
        miVector        *dir_in,
        miVector        *dir_out,
        miVector        *normal,
        miScalar        roughness,
        miColor         *ior);

Calculate the specular color result according to the Cook-Torrance reflection model for incident direction dir_in, reflection direction dir_out at a surface with normal normal. The roughness is the average slope of surface microfacets. ior is the relative index of refraction for three wavelengths (ior_out/ior_in for red, green, and blue). All indices must be 1.0 or greater; if not they are clamped to 1.0. See [Foley 90].

 

    miScalar mi_blinn_specular(
        miVector        *dir_in,
        miVector        *dir_out,
        miVector        *normal,
        miScalar        roughness,
        miScalar        ior);

Like  mi_cooktorr_specular, but only for one wavelength. Only one index of refraction ior is needed, and the result is a scalar. If ior is less than 1.0, it is clamped to 1.0. See [Foley 90].

 

    miScalar mi_blong_specular(
        miVector        *dir_in,
        miVector        *dir_out,
        miVector        *normal,
        miScalar        roughness,
        miScalar        ior);

This is similar to  mi_blinn_specular, but implements a hybrid of Blinn and Phong shading instead of true Blinn shading. It is included separately to support the Softimage Blinn shading model.

 

    miScalar mi_ward_glossy(
        miVector        *dir_in,
        miVector        *dir_out,
        miVector        *normal,
        miScalar        shiny);

Calculate the value of the isotropic Ward glossy reflection model for incident direction dir_in, reflection direction dir_out at a surface with normal normal and shinyness shiny. dir_in should point towards the point, while dir_out and normal should point away from the point. Shiny should be low (for example 5) for wide glossy reflection, and high (for example 100) for narrow glossy (nearly specular) reflection.

 

    miScalar mi_ward_anisglossy(
        miVector        *dir_in,
        miVector        *dir_out,
        miVector        *normal,
        miVector        *u,
        miVector        *v,
        miScalar        shiny_u,
        miScalar        shiny_v);

Calculate the value of the anisotropic Ward glossy reflection model for incident direction dir_in, reflection direction dir_out, surface normal normal, and the anisotropic orientation determined by two perpendicular vectors u and v. The shinyness in the u and v direction is shiny_u and shiny_v, respectively. dir_in should point towards the point, while dir_out and normal should point away from the point. u and v should be perpendicular, and also perpendicular to the normal.

 

    miScalar mi_schlick_scatter(
        miVector        *dir_in,
        miVector        *dir_out,
        miScalar        directionality);

Calculate the value of the Schlick volume scattering model for incident direction dir_in, scattering direction dir_out, and directionality directionality. dir_in should point towards the point, while dir_out should point away from the point. directionality must be between -1 and 1. For values between -1 and 0 it models backscattering (with -1 being the most directional), for a value of 0 it models diffuse (isotropic) scattering, and for values between 0 and 1 it models forward scattering.

 

    miRay_type mi_choose_scatter_type(
        miState         *state,
        float           transp,
        miColor         *diffuse,
        miColor         *glossy,
        miColor         *specular)

In photon shaders it is generally important (although not required) to generate only one photon per photon interaction. To make this happen this function can be used to select one of several new photon types. The function returns: miPHOTON_REFLECT_SPECULAR, miPHOTON_REFLECT_GLOSSY, miPHOTON_REFLECT_DIFFUSE, miPHOTON_TRANSMIT_SPECULAR, miPHOTON_TRANSMIT_GLOSSY, miPHOTON_TRANSMIT_DIFFUSE or miPHOTON_ABSORBED. The return type is based on incoming coefficients and chosen in such a way that the most important component is chosen most often. Notice that for  caustic simulations the diffuse and glossy components are ignored. Also note that the sum of the diffuse, glossy and specular coefficients should be less than or equal to one within each of the red, green, and blue color bands, and that  mi_choose_scatter_type modifies the input coefficients and scales them correctly based on the probability of generating a photon of that type. To obtain a correct result the shader must use the modified coefficients in the computations performed after  mi_choose_scatter_type has been used. The probability for reflection is 1 - transp. See page [*] for a more detailed explanation.

 

    int mi_choose_lobe(
        miState         *state,
        miScalar        r);

In a two-lobed volume scattering model, choose lobe 1 or 2 based on the probability r of the first lobe.

 

    miBoolean mi_lookup_color_texture(
        miColor         *color,
        miState         *state,
        miTag           tag,
        miVector        *coord)

tag is assumed to be a texture as taken from a color texture parameter of a shader. This function checks whether the tag refers to a shader (procedural texture) or an image, depending on which type of color texture statement was used in the .mi file. If tag is a shader, coord is stored in state- >tex, the referenced texture shader is called, and its return value is returned. If tag is an image, coord is brought into the range (0..1, 0..1) by removing the integer part, the image is looked up at the resulting 2D coordinate, and miTRUE is returned. If the texture is marked with the filter keyword, multi-level pyramid filtering is performed, a procedure related to classical mip-mapping. In both cases, the color resulting from the lookup is stored in *color.

 

    typedef struct {
        miScalar        eccmax;
        miScalar        max_minor;
        miScalar        circle_radius;
        miBoolean       bilinear;
        miScalar        spare[10];
    } miTexfilter;

    miBoolean mi_lookup_filter_color_texture(
        miColor         *color,
        miState         *state,
        miTag           tag,
        miTexfilter     *paras,
        miMatrix        ST)

This function provides higher quality filtering than the multi-level pyramid filtering of  mi_lookup_color_texture described above using a transformation ST which transforms the coordinate system centered in the current raster position in  screen space to  texture space. The functions  mi_texture_filter_project and  mi_texture_filter_transform are provided for helping to calculate this transformation matrix.

This function expects that tag does not refer to a  texture shader, that is, it works only on texture images. It will return miFALSE when used with incorrect parameters or if a projection failed.

In the filtering algorithm a circle around the current raster position is projected to an ellipse in  texture space, and returns the average color of all texture pixels inside the ellipse. If the texture defined by tag is a pyramid texture, multi-level lookup of the texture pixels is performed to speed up the filtering. In the algorithm the level calculation is based on the minor radius of the ellipse.

The filtering can be controlled by choosing different values in paras. If paras is a null, default values for medium filter quality are used.

The eccmax field in miTexfilter specifies the maximum allowed eccentricity of the ellipse. The eccentricity is defined by the ratio of the major and minor radius. Under severe projective distortion the ellipse can have a very large eccentricity and too many texture pixels would be covered by the elliptical area, resulting in long rendering times. In order to limit the filtering time in these cases, the eccentricity threshold can be specified. If the eccentricity is greater than this value, the minor radius of the ellipse is made larger allowing for a potentially higher level in the texture image pyramid since the level calculation is based on the minor radius.

In this calculation a level is selected where the minor radius of the ellipse has a maximum length of max_minor texture pixels. In each successive level in the image pyramid the radius is divided by two, and there are fewer pixels inside the elliptical area. The useful range for eccmax is approximately 10 to 30, higher values will result in better antialiasing. For max_minor the range should be 3 to 8. Higher values result in better antialiasing.

The size of the projected screen-space circle can be modified with the circle_radius parameter. Larger values will result in more blurring since the elliptical area is also made larger. Smaller values will increase the aliasing. The useful range for this field is 0.4 to 1.0.

When a magnification area is detected, that is, an area in which the pixels are not compressed (the elliptical area is smaller than a texture pixel), bilinear texture pixel interpolation can be switched on by setting the bilinear field to miTRUE, and resulting in a more blurry image.

See page [*] for an example.

 

    miBoolean mi_lookup_scalar_texture(
        miScalar        *scalar,
        miState         *state,
        miTag           tag,
        miVector        *coord)

This function is equivalent to  mi_lookup_color_texture, except that tag is assumed to refer to a scalar texture shader or scalar image, as defined in the .mi file with a scalar texture statement, and a scalar is looked up returned in *scalar.

 

    miBoolean mi_lookup_vector_texture(
        miVector        *vector,
        miState         *state,
        miTag           tag,
        miVector        *coord)

This function is also equivalent to  mi_lookup_color_texture, except that tag is assumed to refer to a vector texture shader or vector image, as defined in the .mi file with a vector texture statement, and a vector is looked up returned in *vector.

 

    miBoolean mi_texture_filter_project(
        miVector        p[3],
        miVector        t[3],
        miState *const  state,
        miScalar        disc_r,
        miUint          space)

This function helps in calculating the screen to  texture space transformation matrix required by  mi_lookup_filter_color_texture. It projects three points including the current raster position onto the current intersection primitive (state- >pri) plane and calculates the texture coordinates in the intersections. If state- >pri is null, or if the projection fails, miFALSE is returned.

This function assumes that the current intersected object has a  texture space associated and uses space as an index into the  texture space. The three  screen space points are returned in p, the corresponding two dimensional  texture space points are put into t. The first point in the array is always the central raster position (0,0), the others are inside a disc with radius of disc_r from this central position. Note that the points are relative to the central position, absolute  screen space coordinates are not used. The value of disc_r should be set to 0.5 in most cases, since the full pixel is projected to  texture space. However, when there are highly curved objects in the scene, a smaller value can effectively remove projection problems where the projected points are far outside the hit triangle primitive. In  texture filtering example an example is given using this function.

 

    miBoolean mi_texture_filter_transform(
        miMatrix        ST,
        miVector        p[3],
        miVector        t[3])

This function helps in calculating the screen to  texture space transformation matrix required by  mi_lookup_filter_color_texture. The three two dimensional  screen space points in p and the corresponding three two dimensional  texture space points form a linear equation which is solved for the transformation matrix. See page [*] for an example. This function returns miFALSE if the linear equation mentioned above has no solution.

 

    void mi_tri_vectors(
        miState         *state,
        int             which,
        int             ntex,
        miVector        **a,
        miVector        **b,
        miVector        **c)

All the information in the state pertains to the interpolated intersection point in a triangle. This function can be used to obtain information about the uninterpolated  triangle vertices. Together with the  barycentric coordinates in the state, parameters retrieved with  mi_tri_vectors may be interpolated differently by the shader. The which argument is a character that controls which triple of vectors is to be retrieved:

which vector
'p' the points in space
'n' the normal vectors
'm' the motion vectors
't' the texture coordinates of  texture space ntex
'u' the U bump basis vectors
'v' the V bump basis vectors
'U' the first surface derivative in U (dPdu)
'V' the first surface derivative in U (dPdv)
'X' the second surface derivative d2Pdu2
'Y' the second surface derivative d2Pdv2
'Z' the second surface derivative d2Pdudv
'*' the user vectors

A pointer to the vectors is stored in *a, *b, and *c. The shader may not modify these vectors. They are stored in the space used when the scene was created (either  object space or  camera space depending on state - > options - > render_space); the original data is accessed without implicit transformation to  internal space. If the requested triple is not available, miFALSE is returned. This function relies on state - > pri; it only works if the shader has not modified this variable, as some ray-marching volume shaders do.

 

    miBoolean mi_query(
        const miQ_type  query,
        miState *const  state,
        miTag           tag,
        void * const    result,
        ...)

Return various pieces of information about the current state of mental ray. query is the request code specifying what piece of information to query; state is the shader state, tag is the tag of the DB element to query, if any, and result is a pointer to the variable to store the results in. Some queries do not require a tag; in this case miNULLTAG must be passed as tag. Some queries require extra arguments in addition to the four standard arguments.  mi_query returns miFALSE if the queried value is not available or an unknown type code is used.

The following query codes are available:

 

query code state tag result purpose
miQ_VERSION N N char * mental ray version string
miQ_DATE N N char * mental ray compilation date
miQ_NUM_GLOBAL_LIGHTS N N int number of global lights
miQ_GLOBAL_LIGHTS N N miTag * array with global light tags
miQ_NUM_TEXTURES Y N int * # of textures in state->tex_list
miQ_GEO_LABEL N N miUint translator-defined triangle label
miQ_GEO_DATA N N miTag user data block of current object
miQ_PRI_BBOX_MIN Y N miVector bounding box of intersected primitive
miQ_PRI_BBOX_MAX Y N miVector bounding box of intersected primitive
miQ_TILE_PIXELS Y N int[4] lower left and upper right tile pixel coord
miQ_TILE_SAMPLES Y N int[4] same but including filter source margin
miQ_INST_FUNCTION N Y miTag optional procedural transformation
miQ_INST_GLOBAL_TO_LOCAL N Y miMatrix * instance transformation
miQ_INST_LOCAL_TO_GLOBAL N Y miMatrix * inverse instance transformation
miQ_INST_IDENTITY N Y miBoolean miTRUE if identity transformation
miQ_INST_ITEM N Y miTag instanced scene element
miQ_INST_PARENT N Y miTag leaf instance parent (0 otherwise)
miQ_INST_HIDE N Y miBoolean instance is inactive
miQ_INST_VISIBLE N Y miUint visible to primary rays
miQ_INST_TRACE N Y miUint visible to secondary rays
miQ_INST_SHADOW N Y miUint invisible to shadow rays
miQ_INST_CAUSTIC N Y miUint bitmap: 1=enable casting, 2=enable
        receiving, 3=disable casting,
        4=disable receiving
miQ_INST_DECL N Y miTag inherited parameter declaration
miQ_INST_PARAM_SIZE N Y int inherited parameter size
miQ_INST_PARAM N Y void * inherited parameters
miQ_INST_MATERIAL N Y miTag inherited material
miQ_INST_LABEL N Y miUint translator-defined instance label
miQ_INST_DATA N Y miTag user data block
miQ_TRANS_INTERNAL_TO_WORLD Y N miMatrix * internal to  world space transformation
miQ_TRANS_INTERNAL_TO_CAMERA Y N miMatrix * internal to  camera space transformation
miQ_TRANS_INTERNAL_TO_OBJECT Y N miMatrix * internal to  object space transformation
miQ_TRANS_WORLD_TO_INTERNAL Y N miMatrix * world to  internal space transformation
miQ_TRANS_CAMERA_TO_INTERNAL Y N miMatrix * camera to  internal space transformation
miQ_TRANS_OBJECT_TO_INTERNAL Y N miMatrix * object to  internal space transformation
miQ_TRANS_WORLD_TO_CAMERA Y N miMatrix * world to  camera space transformation
miQ_TRANS_WORLD_TO_OBJECT Y N miMatrix * internal to  world space transformation
miQ_TRANS_CAMERA_TO_WORLD Y N miMatrix * camera to  world space transformation
miQ_TRANS_OBJECT_TO_WORLD Y N miMatrix * object to  world space transformation
miQ_GROUP_MERGE_GROUP N Y miBoolean miTRUE if merged or connected
miQ_GROUP_NKIDS N Y int number of child instances
miQ_GROUP_KID N Y miTag nth child (n is fifth argument)
miQ_GROUP_LABEL N Y miUint translator-defined group label
miQ_GROUP_DATA N Y miTag user data block
miQ_OBJ_TYPE N Y int 0=polygonal, 1=surfaces
miQ_OBJ_VISIBLE N Y miBoolean visible to primary rays
miQ_OBJ_TRACE N Y miBoolean visible to secondary rays
miQ_OBJ_SHADOW N Y miBoolean invisible to shadow rays
miQ_OBJ_VIEW_DEPENDENT N Y miBoolean contains view-dependent surfaces
miQ_OBJ_CAUSTIC N Y miUint 0=none, 1=casts, 2=receives, 3=both
miQ_OBJ_LABEL N Y miUint translator-defined object label
miQ_OBJ_DATA N Y miTag user data block
miQ_LIGHT_TYPE N Y int 0=point, 1=directional, 2=spot
miQ_LIGHT_AREA N Y int 0=none, 1=rectangle, 2=disc, 3=sphere
miQ_LIGHT_EXPONENT N Y miScalar distance falloff, n in 1$ \over$rn
miQ_LIGHT_CAUSTIC_PHOTONS N Y int number of caustic photons
miQ_LIGHT_GLOBAL_PHOTONS N Y miColor number of globillum photons
miQ_LIGHT_ENERGY N Y miTag energy for caustics and globillum
miQ_LIGHT_SHADER N Y miTag tag of light shader
miQ_LIGHT_EMITTER N Y miVector tag of light photon emitter shader
miQ_LIGHT_ORIGIN N Y miVector light position
miQ_LIGHT_DIRECTION N Y miVector light direction
miQ_LIGHT_AREA_R_EDGE_U N Y miVector U size of rectangular area light
miQ_LIGHT_AREA_R_EDGE_V N Y miVector V size of rectangular area light
miQ_LIGHT_AREA_D_NORMAL N Y miVector normal vector of disc area light
miQ_LIGHT_AREA_D_RADIUS N Y miScalar radius of disc area light
miQ_LIGHT_AREA_S_RADIUS N Y miScalar radius of spherical area light
miQ_LIGHT_AREA_C_RADIUS N Y miScalar radius of cylinder area light
miQ_LIGHT_AREA_C_AXIS N Y miVector axis of cylinder area light
miQ_LIGHT_AREA_SAMPLES_U N Y int number of samples in U direction
miQ_LIGHT_AREA_SAMPLES_V N Y int number of samples in V direction
miQ_LIGHT_SPREAD N Y miScalar outer cone angle of spot light
miQ_LIGHT_USE_SHADOWMAP N Y miBoolean light has a shadow map
miQ_LIGHT_LABEL N Y int light label
miQ_LIGHT_DATA N Y miTag user data block
miQ_MTL_OPAQUE N Y miBoolean material is opaque to shadow rays
miQ_MTL_SHADER N Y miTag material shader
miQ_MTL_DISPLACE N Y miTag displacement shader
miQ_MTL_SHADOW N Y miTag shadow shader
miQ_MTL_VOLUME N Y miTag volume shader
miQ_MTL_ENVIRONMENT N Y miTag environment shader
miQ_MTL_CONTOUR N Y miTag contour shader
miQ_MTL_PHOTON N Y miTag photon shader
miQ_MTL_PHOTONVOL N Y miTag photon volume shader
miQ_FUNC_USERPTR N Y void * user pointer in shader instance
miQ_FUNC_LOCK N Y miLock * local shader instance lock
miQ_FUNC_TYPE N Y int 0=C/C++, 1=phen., 2=output file
miQ_FUNC_DECL N Y miTag tag of shader declaration
miQ_FUNC_NEXT N Y miTag next shader in shader list
miQ_FUNC_INDIRECT N Y miTag take params from this shader
miQ_FUNC_PARAM_SIZE N Y int size of shader parameters in bytes
miQ_FUNC_RESULT_SIZE N Y int shader result size in bytes
miQ_FUNC_PARAM N Y void * shader parameters
miQ_FUNC_* Y N see above same for state - > shader
miQ_DECL_LOCK N Y miLock * shared by all shader instances
miQ_DECL_TYPE N Y int miTYPE_* result type
miQ_DECL_RESULT_SIZE N Y int result size, 4 unless struct
miQ_DECL_NAME N Y char * shader name
miQ_DECL_PARAM N Y char * ascii-encoded parameter declaration
miQ_DECL_VERSION N Y int shader declaration version
miQ_DECL_* Y N see above same for state - > shader
miQ_IMAGE_WIDTH N Y int width of image in pixels
miQ_IMAGE_HEIGHT N Y int height of image in pixels
miQ_IMAGE_BITS N Y int num of bits per component (8,16,32)
miQ_IMAGE_COMP N Y int num of components (1,2,3,4)
miQ_IMAGE_FILTER N Y miBoolean image allows filtering
miQ_IMAGE_DESATURATE N N miBoolean color frame buffer desaturation mode
miQ_IMAGE_DITHER N N miBoolean color frame buffer dithering mode
miQ_IMAGE_NOPREMULT N N miBoolean color frame buffer premultiplication mode
miQ_IMAGE_GAMMA N N double color frame buffer gamma factor
miQ_DATA_PARAM N Y char * user data contents
miQ_DATA_DECL N Y miTag user data declaration if any, or 0
miQ_DATA_NEXT N Y miTag next user data block in chain, or 0
miQ_DATA_LABEL N Y miUint translator-defined user data label
miQ_DATA_PARAM_SIZE N Y int size of user data block in bytes
miQ_DATA_NEEDSWAP N Y miBoolean requires byte-swapping by shader
         

The ``N'' symbol in the state column indicates that the state is not used. The ``N'' symbol in the tag column means that miNULLTAG must be passed. Some queries can specify a state instead of a tag. Their query codes are indicated with a *, which stands for any of the preceding codes whose names begin with the same prefix; in this case  mi_query will take the current shader (state - > shader) instead of an arbitrary tag. This is slightly faster than passing a tag.

The result type in the table indicates the type of the variable that  mi_query accepts a pointer to: to obtain an integer result from mi_query (the table lists an ``int''), a pointer to an integer must be passed as the fourth argument (``int *''). For  mi_query, ``function'' is synonymous with ``shader''.

The result of the miQ_INST_VISIBLE, miQ_INST_SHADOW, miQ_INST_TRACE, and miQ_INST_CAUSTIC queries depend on whether a scene DAG or  leaf instance tag is passed. A scene DAG instance contains the flags specified by the scene description language when the instance was created. A leaf instance contains the effective instance flags for rendering, that is, with instance inheritance and object flags taken into account. The miQ_INST_VISIBLE etc. modes should be used instead of the miQ_OBJ_VISIBLE etc. modes because they return the same modes that mental ray uses when rendering.

The result vectors of the miQ_LIGHT_ORIGIN and miQ_LIGHT_DIRECTION queries are defined in  internal space if the light instance tag is passed, otherwise the vectors are defined in local space.

The miQ_TILE_* codes are supported by mental ray 2.1.34.107 or later. They describe the location and size of the currently rendered image tile. The returned values are in the order xlow  xhigh  ylow  yhigh. The sampled area may be larger than the tile due to filtering and jittering.

The query codes miQ_NUM_TEXTURES and miQ_GEO_LABEL may only be used if state - > pri has not been modified by the shader or calling shader. Ray-marching volume shaders sometimes clear this state variable. Both are not supported in  displacement shaders. miQ_GEO_LABEL also returns miFALSE if the object is not marked tagged and no polygon/surface labels exist.

Note that a return type of miMatrix * means that the address of a pointer must be passed, not the address of a matrix. This reduces the number of bytes that  mi_query has to copy from 64 (sixteen floats) to only four (or eight, on some CPU architectures).

 

    miBoolean mi_fb_put(
        miState         *state,
        int             fb,
        void            *data)

2.1Store data into the sample so that it gets filtered and stored in  user frame buffer fb later. The type of the data to copy from *data is determined by the frame buffer type as defined in the options block. The  frame buffer number fb must be in the range 0...7. If this frame buffer was not defined, this function has no effect and returns miFALSE. The data is stored in the current sample (i.e., the current location for which the primary ray was cast), and is filtered to create frame buffer pixels after all samples in the region have been taken. There is no way to store user frame buffer data in arbitrary locations with this function. It should be called for all samples and all defined user frame buffers to avoid leaving holes; if user frame buffer data is left undefined in a sample because  mi_fb_put was not called, the data defaults to zero and is filtered as such. Output shaders may not use this function because there is no notion of ``samples'' during output shading; instead, they must use the standard  mi_img_put_* functions with an offset of miRC_IMAGE_USER + fb. Shaders may get the data type of a frame buffer n by inspecting state - > options - > image_types[n].

 

    miBoolean mi_fb_get(
        miState         *state,
        int             fb,
        void            *data)

2.1Retrieve data from  user frame buffer fb. The type of the data copied to *data is determined by the frame buffer type as defined in the options block. It will never be larger than 16 bytes (the size of a miColor). The frame buffer number fb must be in the range 0...7. If this frame buffer was not defined, this function returns miFALSE, and no data is stored. This function is intended to let shaders retrieve data that may have been stored by shaders called in later ray generations, but like mi_fb_put it is limited to the current sample. Again, output shaders may not use this function because there is no notion of ``samples'' during output shading; instead, they must use the standard mi_img_get_* functions with an offset of miRC_IMAGE_USER + fb.

 

    miBoolean mi_geoshader_add_result(
        miTag           *result,
        const miTag     item)

This function should be called from  geometry shaders for adding a scene element to the result. If result or item are null, miFALSE is returned. If result refers to a null tag, an  instance group is created and returned in result. If result is non-null but does not refer to an instance group, an instance group is created, the result element is put into this group and the group is returned in result. Now that this function has enforced that an instance group element is always returned, the item element is put into the returned group. See page [*] for an example.

 

    miBoolean mi_geoshader_tesselate(
        miState         *state,
        miTag           *leaves,
        miTag           source)

This function should be called from  geometry shaders only. It builds a list of instances that describes the object,  instance group, or  instance source. If source contains more than one object, there will be multiple instances in the leaves list. The leaves argument is set to the tag of the first instance; the others are chained to one another with the next field in each instance. The last instance in the list has a null next field.

The tessellation function also tessellates the geometry described by each instance, and attaches the triangles resulting from the tessellation to the boxes field of the instance. Triangles are stored in  boxes, which are data structures consisting of a header, a vector list, a vertex list, and a triangle list. Boxes have a maximum size; if an object does not fit into one box more are generated and chained using the next_box tag in each box. See chapter [*] for more detail.

 

    miBoolean mi_geoshader_tesselate_end(
        miTag           leaves)

Release all memory allocated by  mi_geoshader_tesselate. This function releases all instances and boxes attached to the instance chain leaves, which was created by  mi_geoshader_tesselate. Multiple instance lists can exist at the same time; it is not necessary to release one before creating the next but since memory demands may be substantial if the tessellated geometry is large, it is recommended to not keep instance lists longer than necessary.

 

    miBoolean mi_string_substitute(
        char            *newname,
        char            *name,
        long            size)

This function3.2 performs substitutions on the file path name, and returns the substituted path in newname, which must point to a char buffer of sufficient size (miPATHSIZE is recommended). The size of the buffer must be passed as size to prevent buffer overruns. Substitutions are taken from the  MI_RAY_SUBSTITUTE environment variable, the mental ray registry mechanism, and the (obsolete) Softimage Linktab mechanism. For details on the first two refer to [Driemeyer 99].

 

    miBoolean mi_inclusive_lightlist(
        int       *n_lights,
        miTag     **lights,
        miState   *state)

This function accepts a list of  light source instances, and returns a modified list that includes all other instances of the instanced lights as well. If a light is instanced three times in the scene, and one (or more) of them appears in *lights, then *lights will contain all three after this call. n_lights points to an integer containing the original list size, and lights points to a pointer to the original list. After the function returns, the integer holds the new list length, and the pointer points to a new list. Both the integer and the pointer should be on the stack and should be initialized from the shader parameters using  mi_eval to avoid overwriting the actual shader parameters, which should remain intact for the next shader call.

The new list is a copy of the  global light list (see  mi_query) with only those lights that match the passed original list included. The returned list remains valid until the next call to  mi_inclusive_lightlist or  mi_exclusive_lightlist. Note that this function involves a loop over all lights, and may be a good candidate for calling once in the  init shader instead of once every time the shader is called, if *lights is known to be constant during the frame.

 

    miBoolean mi_exclusive_lightlist(
        int       *n_lights,
        miTag     **lights,
        miState   *state)

This function is similar to the previous, but returns all global light instances except those whose instanced light match a light instanced in the given list. Both functions return mutually exclusive lists when called with the same argument list. n_lights points to an integer containing the original list size, and lights points to a pointer to the original list. After the function returns, the integer holds the new list length, and the pointer points to a new list. Both the integer and the pointer should be on the stack and should be initialized from the shader parameters using  mi_eval to avoid overwriting the actual shader parameters, which should remain intact for the next shader call.

The new list is a copy of the  global light list (see  mi_query) with the matches with the original list removed. This function is slightly slower than the previous. The returned list remains valid until the next call to  mi_inclusive_lightlist or  mi_exclusive_lightlist.

3.21.10 Obsolete Auxiliary Functions

These functions are obsolete; use  mi_query for future implementations.

 

    void mi_light_info(
        miTag           tag,
        miVector        *org,
        miVector        *dir,
        void            **paras)

tag is assumed to be a  light source  instance as found in a light parameter of a shader, or returned by  mi_query. It is looked up, and its origin (location in  internal space) is stored in *org, and its direction (also in  internal space) is stored in *dir. If tag refers to a light source instead of the instance, both vectors are defined in local space. Since light sources can only have one or the other but not both, the unused vector is set to a null vector. This can be used to distinguish directional (infinite) light sources; their org vector is set to (0, 0, 0). The paras pointer is set to the shader parameters of the referenced light shader; if properly cast by the caller, it can extract information such as whether a non-directional light source is a point or a spot light, and its color and attenuation parameters. (mental ray considers a spot light to be a point light with directional attenuation.) Any of the three pointers org, dir, and paras can be a null pointer.

 

    int mi_global_lights_info(
        miTag           **tag)

Returns the address of an array containing all global light  leaf instances. The tags in this array can be used like light shader parameters for calls to  mi_sample_light and  mi_light_info. One important difference between shader light parameters and global lights is that global lights are the result of instancing, so if a light is transformed and/or multiply instanced it will appear transformed and/or more than once in the  global light list, while shader parameters will be accessed as stored in the scene with no instancing applied. It is recommended that translators that support multiple light instancing use material shaders that use the  global light list instead of a light array in the shader parameter list (which, however, may still be useful as an argument for  mi_inclusive_lightlist and  mi_exclusive_lightlist).

 

    void mi_texture_info(
        miTag           tag,
        int             *xres,
        int             *yres,
        void            **paras)

tag is assumed to be a texture as found in a texture parameter of a shader. If tag refers to a procedural  texture shader, *xres and *yres are set to 0 and *paras is set to the shader parameters of the texture shader. If tag is an image texture, *xres and *yres are set to the image resolution in pixels, and *paras is set to 0. Any of the three pointers can be a null pointer.

 

    void *mi_shader_info(
        miState         *state)

Returns a pointer to the user pointer of the current shader in the state, state - > shader. This is useful for shader that allocate memory during startup (in the instance  init shader) and need a place to store the pointer to the initialized data in a place where shader instances can pick it up. A unique user pointer is returned for each shader instance (each unique function/parameters pair).

 

    int mi_instance_info(
        miState         *state,
        void ** const   paraspp,
        void ** const   spare1,
        void ** const   spare2,
        void ** const   spare3)

Returns the size of and a pointer to the inherited instance parameters. Instance parameters are attached to the instances of the scene DAG, and are combined in a scene DAG traversal step during scene preprocessing, before rendering begins. The structure of the inherited data is determined by the inheritance function, not by the shader, and is generally under control of the translator that generated the scene. Typically, all instances contain either no parameters at all (size 0), or they all use the same data structure. The instance being checked is state - > instance. The spare pointers must be passed as 0.

3.21.11 Contour Functions

 

    miBoolean mi_get_contour_line(
        miContour_endpoint *p1,
        miContour_endpoint *p2);

This function can be used by a  contour output shader to get end points of a  contour line segment. When  mi_get_contour_line returns miFALSE, there are no more contour lines.

 

    void mi_add_contour_lines(
        miContour_endpoint p1[],
        miContour_endpoint p2[],
        int                n);

This is another function available to contour output shaders. It adds extra  contour lines to the ones that were found during rendering. p1 is the list of first endpoints, p2 is the list of second endpoints, and n is the number of contour lines to be added (the number of elements in the lists). This can for example be used by a combination of two contour output shaders: the first one adds some extra contour lines, and the second one renders all contour lines (both the contour lines found during rendering and the extra contour lines added using  mi_add_contour_lines). Or, as another example, the first contour output shader can read all contour lines, analyze them, and write back a subset of them (or even some altogether different contours) with  mi_add_contour_lines.

3.21.12 Memory Allocation

mental ray's memory allocation functions replace the standard malloc packages found on most systems. They have built-in functions for memory leak tracing and consistency checks, and handle errors automatically. Shaders should always use these functions and not malloc or similar libc functions directly.

 

    void *mi_mem_allocate(
        const int     size)

Accepts one argument specifying the size of the memory to allocate. A pointer to the allocated memory is returned. If the allocation fails, an error is reported automatically, and mental ray tries to recover memory or aborts if this fails. This call is guaranteed to return a valid pointer, or not to return at all. The allocated memory is zeroed. This and most other mem_* functions use locking and should therefore not be used in time-critical places to prevent  multithreading  efficiency from dropping through the floor. See page [*] for details on the effect of locks on efficiency. A good place for memory allocation is  init shaders.

 

    void *mi_mem_reallocate(
        void * const  mem,
        const int     size)

Change the size of an allocated block of memory. There are two arguments: a pointer to the old block of memory, and the requested new size of that block. A pointer to the new block is returned, which may be different from the pointer to the old block. If the old pointer was a null pointer,  mi_mem_reallocate behaves like mi_mem_allocate. If the new size is zero,  mi_mem_reallocate behaves like  mi_mem_release, and returns a null pointer. If there is an allocation error, an error is reported and raylib is aborted. Like  mi_mem_alloc,  mi_mem_reallocate never returns if the re-allocation fails. If the block grows, the extra bytes are zeroed.

 

    void mi_mem_release(
        void * const  mem)

Frees a block of memory. There is one argument: the address of the block. If a null pointer is passed, nothing is done. There is no return value. After releasing memory it may no longer be accessed.

3.21.13 Thread Parallelism and Locks

    In addition to network parallelism, mental ray also supports shared memory parallelism through  threads. Network parallelism is a form of distributed memory parallelism where processes cooperate by exchanging messages. Messages are used to exchange data as well as to synchronize. With  shared memory data can easily be exchanged, a process must only access the common memory to do so. A different mechanism has to be used for synchronization. This is usually done by locking. Basically what has to be done is one process has to tell the other that it is waiting to access data, and another process can signal that it has finished working with it, so that any other process may now access it.

By default  threads are used on shared memory multiprocessor machines. Threads are sometimes also called lightweight processes. Threads behave like processes running on a common shared memory.

Since memory is shared between two threads, both can write to memory at the same time. It can also happen that one thread writes while another reads the same memory. Both these cases can lead to surprising unwanted results. Therefore - to guard against these surprises - when using threads certain precautions have to be observed. Care has to be taken when using heap memory such as global or static data, as any thread may potentially modify it. To prevent corrupting any data (or reading corrupted data), locking must be used when it is not otherwise guaranteed that concurrent accesses  will not occur. The stack, however, is always safe because every thread has its own stack that is not shared with any other thread.

In addition to making sure that write accesses to data are performed when no other thread accesses the data, it is important to use only so-called concurrency safe libraries and calls. If a call to a non reentrant function is done, locking should be used. A function is called reentrant if it can be executed by multiple threads at the same time without adverse effects. (Reentrancy and concurrency safety are related, but the terms stem from different historical contexts, and reentrancy also implies the ability to recurse safely.) Details and examples are explained below.

For example, static data on a shared memory multiprocessor can be modified by more than one processor at a time. Consider this test:

    static miBoolean is_init = miFALSE;
    ...
    if (!is_init) {
        is_init = miTRUE;
        initialize();
    }

This does not guarantee that initialize is called only once. The reason is that all threads share the is_init flag, so two threads may simultaneously examine the flag. It is possible that both will find that it has not been set, and enter the if body. Next, both will set the flag to miTRUE, and then both will call the initialize function. This situation is called a  race condition. The example is contrived because initialization and termination should be done with init and exit shaders as described in the next section, but this problem can occur with any heap variable. Even incrementing global or static variables with ``++'' is not safe - the time window that leads to errors may be small, but that makes such mistakes all the more difficult to find. In general, all threads on a host share all data except local auto variables on the stack.

The behavior described above could also occur if more than one thread is used on a single processor, but by default mental ray does not create more threads than there are processors.

 There are two methods for guarding against  race conditions. One is to guarantee that only one thread executes certain code at a time. Such code surrounded by lock and unlock operations is called a  critical section. Code inside of critical sections may access global or static data or call any function that does so (as long as all is protected by the same lock). The lock used in this example is assumed to have been created and initialized with a call to  mi_init_lock before it used here. (See below how locks are initialized.) Here is an example of how a critical section may be used:

    miLock lock;

    mi_lock(lock);
    if (!is_init) {
        is_init = miTRUE;
        initialize();
    }
    mi_unlock(lock);

The other method is to use separate variables for each thread. This is done by allocating an array with one entry for each thread, and indexing this array with the current thread number (which can be found in state - > thread). Allocation is done in the shader's initialization function (which has the same name as the shader with _init appended). No locking is required because it is called only once. The termination function (which also has the same name but with _exit appended) must release the array.

 Locks reduce  multithreading  efficiency and should be used only when absolutely necessary. The probability of one thread blocking because another has locked a section of code grows very quickly with the number of threads, and a thread that is blocked is not available to do useful work. Efficiency describes the degree of parallelism: if n threads increase the speed by a factor m, then the efficiency is m$ \over$n. If two threads have an efficiency of 0.95, then 32 threads have an efficiency of only 0.9532 $ \approx$ 0.19, so over 80% of all CPU cycles are wasted! Efficiency drops surprisingly quickly, so careful attention to locks is required. Note that memory allocation and releasing functions ( mi_mem_allocate et. al.) contain a lock.

mental ray provides two locks for general use: state- >global_lock is a lock shared by all threads and all shaders. No two critical sections protected by this lock can execute simultaneously on this host. The second is state- >shader- >lock, which is local to all instances of the current shader. The lock is tied to the shader, not the particular call with particular shader parameters. Every shader in mental ray, built-in or dynamically linked, has exactly one such lock. mental ray internally uses this lock and the global lock to guarantee that the init and exit shaders of a shader do not execute concurrently. Therefore, they must not be used in these functions.

The relevant functions provided by the parallelism modules are:

 

    void mi_init_lock(
        miLock * const  lock)

Before a lock can be used by one of the other locking functions, it must be initialized with this function. Note that the lock variable must be static or global. Shaders will normally use this function in their _init function. Shaders should not initialize (or delete) state - > global_lock or the local shader lock; they are pre-initialized by mental ray.

 

    void mi_delete_lock(
        miLock * const  lock)

Destroy a lock. This should be done when it is no longer needed. The code should use lock and immediately unlock the lock first to make sure that no other thread is in or waiting for a critical section protected by this lock. Shaders will normally use this function in their exit shader. Do not delete the predefined locks.

 

    void mi_lock(
        const miLock    lock)

Check if any other code holds the lock. If so, block; otherwise set the lock and proceed. This is done in a parallel-safe way so only one  critical section locked can execute at a time. Note that locking the same lock twice in a row without anyone unlocking it will block the thread forever, effectively freezing mental ray, because the second lock can never succeed.

 

    void mi_unlock(
        const miLock    lock)

Release a lock. If another thread was blocked attempting to set the lock, it can proceed now. Locks and unlocks must always be paired, and the code between locking and unlocking must be as short and as fast as possible to avoid defeating parallelism. There is no fairness guarantee that ensures that the thread that has been blocked for the longest time is unblocked first.

 

    miVpu mi_par_localvpu(void)
        int   miTHREAD(miVpu vpu)
        int   miHOST(miVpu vpu)
        miVpu miVPU(int host, int thread)

  The term VPU stands for Virtual Processing Unit. All threads on the network have a unique VPU number.  mi_par_localvpu returns the VPU number of the VPU this thread is running on. VPUs are a concatenation of the host number and the thread number, both numbered from 0 to the number of hosts or threads, respectively, minus 1. (Future versions of mental ray may use noncontiguous host numbers, but not noncontiguous thread numbers.)

The  miTHREAD macro extracts a thread number from a VPU, and the  miHOST macro extracts the host number from a VPU. Thread 0 is called the client thread; host 0 is called the client host. Thread 0 on host 0 is normally running the translator that controls the entire operation. The  miVPU macro puts a host and thread number together to form a VPU number. The  mi_par_localvpu function returns the VPU of the current thread on the local host.

In a shader the fastest way of finding the current thread number is state - > thread.

 

    int mi_par_nthreads(void)

Returns the number of threads on the local host. This is normally 1on a single-processor system. This number can be used to allocate an array of per-thread variables in the shader initialization code. The array can then be indexed by the shader with state - > thread.

 

    int mi_par_aborted(void)

Return a nonzero value if mental ray has been aborted, and the shader should stop what it is doing, clean up, and return. This is only of interest in  output shaders because they can run for a long time. This allows the user to press on an  abort button, which causes calls to  mi_pat_aborted to return nonzero, and have the shader return as soon as possible. For example, the shader might call this function in its scanline loop (not for every pixel to avoid slowing it down), and skip the remaining lines. The shader must still clean up, for example releasing memory that it has allocated.

3.21.14 Messages and Errors

  Shaders may print messages and errors. They are printed in the same format as rendering (RC) messages. Options given to the translator determine which messages are printed and which are suppressed. All message routines have the same parameters as printf(3). All append a newline to the message. Messages are printed in the form

        RC host.thread level: message

with the module name, e.g. RC, the host number host if available, the thread number thread with a leading dot if available, the message type level (fatal, error, warning etc), and the message given in the function call. In a networked environment, the messages of servers are usually transferred to the client rendering host and printed in the order they were received. Messages resulting from connection problems and those that were dropped to avoid a network overload may be found in a local file (/tmp/raylib.log). Newlines in the message are replaced with blanks.

 

    void mi_fatal(
        const char * const message,
        ...)

An unrecoverable error has occurred. Unlike all others, this call will not return; it will attempt to recover mental ray and return to the top-level translator. Recovering may involve aborting all operations in progress and clearing the entire database. Fatal messages can be suppressed, but mental ray is always exited. This function should never be used in a shader because it may also exit any application that mental ray is embedded in, without giving the user a chance to save his work!

 

    void mi_error(
        const char * const message,
        ...)

An unrecoverable error has occurred. The caller then aborts the current operation gracefully and returns.

 

    void mi_warning(
        const char * const message,
        ...)

A recoverable error occurred. The current operation proceeds.

 

    void mi_info(
        const char * const message,
        ...)

Prints information about the current operation such as the number of triangles and timing information. Infos should be used sparingly; do not print information for every intersection point or shader call except during debugging, especially on Windows NT 4.x with its slow and nonparallel I/O system.

 

    void mi_progress(
        const char * const message,
        ...)

Prints progress reports such as rendering percentages.

 

    void mi_debug(
        const char * const message,
        ...)

Prints debugging information useful only for shader development.

 

    void mi_vdebug(
        const char * const message,
        ...)

Prints more debugging information useful only for shader development. Messages that are likely to be useful only in rare circumstances, or that generate a very large number of lines should be printed with this function.

Note that all these functions incur some runtime overhead even if the verbosity level is set such that no message is printed. It is often a good idea to enclose shader debugging messages that occur frequently in ifdef DEBUG statements to make sure they are omitted in production versions of the shader.

3.21.15 Callable Functions by Shader Type

 The following table describes which shader interface functions are available in which types of shaders:

G  geometry shader
D  displacement shader
P  photon shader and  photon volume shader
E photon emitter shader
Le  lens shader
M  material shader and  texture shader
T  texture shader
V  volume shader
Lg  light shader
S  shadow shader
Cs  contour store shader
C  contour contrast shader and  contour shader
O  output shader

The rules for  init shaders and exit shaders are the same as for the main shader they apply to.

In the following table, ``Y'' means that the function may be used, ``N'' means that it may not be used, and ``O'' means that it is available but is not normally useful. Asterisks ``*'' denotes omission unless an earlier more specific table row overrides it. For example, mi_eval* means all functions beginning with mi_eval, including mi_eval itself, mi_eval_boolean, and so on.

function G D P E Le M V Lg S Cs C O
Shader Calls                        
mi_call_shader* Y Y Y Y Y Y Y Y Y Y Y Y
mi_call_material N N N N N Y N N N N N N
mi_call_photon_material N N Y N N N N N N N N N
mi_eval* N Y Y Y N Y Y Y Y Y N N
mi_flush_cache N Y Y Y N Y Y Y Y Y N N
DB                        
mi_db_* Y Y Y Y Y Y Y Y Y Y Y Y
RC Functions                        
mi_trace_eye N N N N Y N N N N O O N
mi_trace_reflection N N Y Y Y Y Y Y Y O O N
mi_trace_refraction N N Y Y Y Y Y Y Y O O N
mi_trace_transparent N N Y Y Y Y Y Y Y O O N
mi_trace_environment N N Y Y Y Y Y Y Y O O N
mi_trace_probe2.1 N N Y Y Y Y Y Y Y O O N
mi_trace_light N N Y Y Y Y Y N N O O N
mi_sample_light N N Y Y Y Y Y N N O O N
mi_trace_shadow N N N N N N N Y N N N N
mi_trace_shadow_seg N N N N N N N N Y N N N
mi_compute_irradiance N N N N Y Y Y Y Y Y N N
mi_compute_volume_irradiance N N N N Y Y Y Y Y Y N N
mi_sample2.1 N N Y Y Y Y Y Y Y Y Y Y
RC Photon Functions                        
mi_photon_light N N Y N N N N N N N N N
mi_photon_reflection_specular N N Y N N N N N N N N N
mi_photon_reflection_glossy2.1 N N Y N N N N N N N N N
mi_photon_reflection_diffuse2.1 N N Y N N N N N N N N N
mi_photon_transmission_specular N N Y N N N N N N N N N
mi_photon_transmission_glossy2.1 N N Y N N N N N N N N N
mi_photon_transmission_diffuse2.1 N N Y N N N N N N N N N
mi_photon_transparent N N Y N N N N N N N N N
mi_photon_volume_scattering N N Y N N N N N N N N N
mi_store_photon N N Y N N N N N N N N N
mi_store_volume_photon N N Y N N N N N N N N N
RC Direction Functions                        
mi_reflection_dir O Y Y Y Y Y Y Y Y Y Y O
mi_reflection_dir_specular O Y Y Y Y Y Y Y Y Y Y O
mi_reflection_dir_glossy O Y Y Y Y Y Y Y Y Y Y O
mi_reflection_dir_anisglossy O Y Y Y Y Y Y Y Y Y Y O
mi_reflection_dir_diffuse O Y Y Y Y Y Y Y Y Y Y O
mi_refraction_dir O Y Y Y Y Y Y Y Y Y Y O
mi_transmission_dir_specular O Y Y Y Y Y Y Y Y Y Y O
mi_transmission_dir_glossy O Y Y Y Y Y Y Y Y Y Y O
mi_transmission_dir_anisglossy O Y Y Y Y Y Y Y Y Y Y O
mi_transmission_dir_diffuse O Y Y Y Y Y Y Y Y Y Y O
mi_scattering_dir_diffuse O Y Y Y Y Y Y Y Y Y Y O
mi_scattering_dir_directional O Y Y Y Y Y Y Y Y Y Y O
mi_scattering_pathlength O Y Y Y Y Y Y Y Y Y Y O
IMG Functions                        
mi_img_put_* Y Y Y Y Y Y Y Y Y Y Y Y
mi_img_get_* Y Y Y Y Y Y Y Y Y Y Y Y
Math Functions                        
mi_point_to_* N Y Y Y Y Y Y Y Y Y Y N
mi_point_from_* N Y Y Y Y Y Y Y Y Y Y N
mi_vector_to_* N Y Y Y Y Y Y Y Y Y Y N
mi_vector_from_* N Y Y Y Y Y Y Y Y Y Y N
mi_normal_to_* N Y Y Y Y Y Y Y Y Y Y N
mi_normal_from_* N Y Y Y Y Y Y Y Y Y Y N
mi_vector_* Y Y Y Y Y Y Y Y Y Y Y Y
mi_matrix_* Y Y Y Y Y Y Y Y Y Y Y Y
mi_point_* Y Y Y Y Y Y Y Y Y Y Y Y
Noise Functions                        
mi_par_random N N N N Y Y Y Y Y Y Y N
mi_*random Y Y Y Y Y Y Y Y Y Y Y Y
mi_spline Y Y Y Y Y Y Y Y Y Y Y Y
mi_noise_* Y Y Y Y Y Y Y Y Y Y Y Y
mi_unoise_* Y Y Y Y Y Y Y Y Y Y Y Y
Auxiliary Functions                        
mi_fresnel N Y Y Y Y Y Y Y Y Y Y Y
mi_fresnel_reflection N Y Y Y Y Y Y Y Y Y Y Y
mi_phong_specular N Y Y Y Y Y Y Y Y Y Y Y
mi_fresnel_specular N Y Y Y Y Y Y Y Y Y Y Y
mi_blinn_specular N Y Y Y Y Y Y Y Y Y Y Y
mi_blong_specular N Y Y Y Y Y Y Y Y Y Y Y
mi_cooktorr_specular N Y Y Y Y Y Y Y Y Y Y Y
mi_ward_glossy N Y Y Y Y Y Y Y Y Y Y Y
mi_ward_anisglossy N Y Y Y Y Y Y Y Y Y Y Y
mi_schlick_scatter N Y Y Y Y Y Y Y Y Y Y Y
mi_choose_scatter_type N Y Y Y Y Y Y Y Y Y Y Y
mi_choose_lobe N Y Y Y Y Y Y Y Y Y Y Y
mi_lookup_*_texture Y Y Y Y Y Y Y Y Y Y Y Y
mi_texture_filter_project N Y Y Y Y Y Y Y Y Y Y Y
mi_texture_filter_transform N Y Y Y Y Y Y Y Y Y Y Y
mi_tri_vectors N N Y Y N Y Y Y Y Y Y N
mi_query Y Y Y Y Y Y Y Y Y Y Y Y
mi_fb_put2.1 N N N N Y Y Y Y Y Y Y N
mi_fb_get2.1 N N N N Y Y Y Y Y Y Y N
mi_geoshader_add_result Y N N N N N N N N N N N
mi_geoshader_tesselate Y N N N N N N N N N N N
mi_geoshader_tesselate_end Y N N N N N N N N N N N
mi_string_substitute2.1 Y Y Y Y Y Y Y Y Y Y Y Y
Obsolete Auxiliary Functions                        
mi_*_info N Y Y Y Y Y Y Y Y Y Y Y
Contour Functions                        
mi_get_contour_line N N N N N N N N N N N Y
mi_add_contour_lines N N N N N N N N N N N Y
Memory Allocation                        
mi_mem_* Y Y Y Y Y Y Y Y Y Y Y Y
Thread Parallelism and Locks                        
mi_init_lock Y Y Y Y Y Y Y Y Y Y Y Y
mi_delete_lock Y Y Y Y Y Y Y Y Y Y Y Y
mi_lock Y Y Y Y Y Y Y Y Y Y Y Y
mi_unlock Y Y Y Y Y Y Y Y Y Y Y Y
mi_par_localvpu Y Y Y Y Y Y Y Y Y Y Y Y
mi_par_nthreads Y Y Y Y Y Y Y Y Y Y Y Y
mi_par_aborted Y Y Y Y Y Y Y Y Y Y Y Y
Messages and Errors                        
mi_fatal Y Y Y Y Y Y Y Y Y Y Y Y
mi_error Y Y Y Y Y Y Y Y Y Y Y Y
mi_warning Y Y Y Y Y Y Y Y Y Y Y Y
mi_info Y Y Y Y Y Y Y Y Y Y Y Y
mi_progress Y Y Y Y Y Y Y Y Y Y Y Y
mi_debug Y Y Y Y Y Y Y Y Y Y Y Y
mi_vdebug Y Y Y Y Y Y Y Y Y Y Y Y
                         

See page [*] for a similar table listing available state variables.



Footnotes

... function3.2
This function was introduced in mental ray 2.1.36.

next up previous contents
Next: 3.22 Initialization and Cleanup Up: 3. Using and Writing Previous: 3.20 Contours
Copyright 2000 by mental images