Keywords: main

Next: 3.22 Initialization and Cleanup Up: 3. Using and Writing Previous: 3.20 Contours
Subsections

- 3.21.1 DB Functions
- 3.21.2 RC Functions
- 3.21.3 Sampling with mi_sample
- 3.21.4 RC Photon Functions
- 3.21.5 RC Direction Functions
- 3.21.6 IMG Functions
- 3.21.7 Math Functions
- 3.21.8 Noise Functions
- 3.21.9 Auxiliary Functions
- 3.21.10 Obsolete Auxiliary Functions
- 3.21.11 Contour Functions
- 3.21.12 Memory Allocation
- 3.21.13 Thread Parallelism and Locks
- 3.21.14 Messages and Errors
- 3.21.15 Callable Functions by Shader Type

# 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 `double`s 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 = piki,

where pi are the prime numbers, i.e. p1 = 2, p2 = 3, etc., and ki *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 + sr1 |  |  |
dg + gg + sg1 |  |  |
db + gb + sb1 |  |  |

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 + sr, dg + gg + sg, db + gb + sb).

The probability for absorption is

1 - P.

The probability for diffuse reflection2.1 is

P . (1 - t) .

while the probability for diffuse transmission2.1 is

P . t . .

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 . (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)

a

        void mi_vector_normalize(
            miVector    *r)

r : = (If r is a null vector, leave r unchanged.)

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

r : =

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

r : =

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

        miScalar mi_vector_dist(
            miVector    *a,
            miVector    *b)

a - b

        void mi_matrix_null(
            miMatrix     r)

`R` : =

        void mi_matrix_ident(
            miMatrix     r)

`R` : =

        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:

+

        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 1rn
`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 n. If two threads have an efficiency of 0.95, then 32 threads have an efficiency of only 0.9532 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: 3.22 Initialization and Cleanup Up: 3. Using and Writing Previous: 3.20 Contours