Built-in shaders exist to support SOFTIMAGE and Wavefront compatibility. All shaders are described by listing their parameters, both in .mi scene file format and as a C structure. The C structure is particularly useful if custom shaders are written that improve on the operation of existing shaders by building or re-using the C structures of existing shaders and calling them, and modifying the results.
The shading models supported by the SOFTIMAGE and Wavefront material are given as equations, which use the following variables:
ns is the shinyness, d is the transparency, t is the refraction, nr is the reflectivity, ka is the ambient color, kd is the diffuse color, ks is the specular color, ft is the transmission filter, N is the surface normal, V is the vector pointing at the viewer, n is the number of light sources, Li is the vector pointing at light i, H is the vector halfway between V and the direction of the reflection, Hi is the vector halfway between V and Li f is the Fresnel function. Ii is the intensity contributed by light i, Ir is the intensity contributed by reflection, and It is the intensity contributed by transmission (transparency).
Note that the Wavefront dissolve parameter is equivalent to 1 - transparency in mental ray.
Seven shaders implement SOFTIMAGE compatibility. The material and light shader are controlled by a mode parameter that controls which behavior is desired. There are also five compatibility shaders that are no longer required for SOFTIMAGE compatibility, but were present in version 1.8 of mental ray and are still supported to allow version 1.8 .mi scene files to be read. These shaders are not recommended for new developments and may not be supported in future versions of mental ray.
name operation
soft_material material shader, also used as shadow shader soft_color 2D texture shader soft_color_3d 3D texture shader soft_vertex_color RGB vertex color shader soft_vertex_color_alpha RGBA vertex color shader soft_light light shader: point, infinite, spot soft_displace displacement shader soft_env_sphere spherical environment shader soft_fog standard fog volume shader soft_layered_fog layered fog volume shader lens_depth_of_field depth-of-field lens shader
soft_shadow obsolete shadow shader, calls soft_material soft_point point light shader, calls soft_light soft_infinite directional light shader, calls soft_light soft_spot spot light shader, calls soft_light
If any of these shaders is used in a .mi scene file, the scene file must include the softimage.mi header file that contains the shader declarations, using a $include command (see include command) . The C structures are declared in a file mi_softshade.h, to be included in the C source file of custom shaders making direct calls to SOFTIMAGE shaders. Note that these files must always match the version of mental ray, or shaders will operate incorrectly or even crash.
(see material shader) The material shader implements constant, Lambert, Phong, and Blinn shading. Its operation includes inside/outside determination, texture evaluation, light illumination, reflection, and transparency.
This shader can also be used as a shadow shader; it recognizes this case automatically and performs the subset of the material evaluation required for determining the color of light transmitted by the material. This includes testing whether the light that cast the shadow ray is in the shadow material's light list, collecting the diffuse and transparency contributions of textures only, and calculating the resulting transmission color. All other operations are omitted. The material shader considers itself a shadow shader if the state variable type has the value miRAY_LIGHT.
For a general explanation of shading in computer graphics, refer to [Hall 89] or [Foley 90]. The illumination of a surface using Phong mode is computed according to
Blinn mode differs from the Phong mode in that it attenuates the specular highlights by a geometrical attenuation factor G (see [Foley 90]). The illumination of a surface with this material is computed according to
Lambert mode only calculates the contribution of the ambient color and diffuse color and omits the specular component.:
Constant shading simply assigns the diffuse color, without actually performing illumination calculation, and disregards both the ambient color and specular color:
The material shader has the following .mi scene file declaration:
declare "soft_material" ( integer "mode", # 0=flat, 1=lambert, 2=phong, 3=blinn color "ambient", color "diffuse", color "specular", color "ambience", scalar "shiny", scalar "transp", scalar "reflect", scalar "ior", array struct "texture" { color texture "map", integer "space", integer "mask", integer "comp", integer "method", scalar "blend", scalar "ambient", scalar "diffuse", scalar "specular", scalar "transp", scalar "reflect", scalar "bump", scalar "u_unit", scalar "v_unit", scalar "u_wrap", scalar "v_wrap", boolean "blackwhite" }, array light "lights", boolean "sblur", scalar "sblurdecay", boolean "notrace", array light "difflights" )
The corresponding C structure is:
struct soft_material { miInteger mode; /* flat,lmb,phong,blinn*/ miColor ambient; /* ambient color */ miColor diffuse; /* diffuse color */ miColor specular; /* specular color */ miColor ambience; /* ambience factor */ miScalar shiny; /* specular decay */ miScalar transp; /* transparency */ miScalar reflect; /* reflectivity */ miScalar ior; /* refraction index */ int i_texture; /* index of 1st texture*/ int n_texture; /* number of textures */ struct Tex { miTag map; /* texture file */ miInteger space; /* texture vertex space*/ miInteger mask; /* 0=none,1=alpha,2=int*/ miInteger comp; /* 1=alpha,2=intens */ miInteger method; /* 0..4=XY,YZ,XZ,UV,cyl*/ miScalar blend; /* overall blending */ miScalar ambient; /* ambient weight */ miScalar diffuse; /* diffuse weight */ miScalar specular; /* specular weight */ miScalar transp; /* transparency weight */ miScalar reflect; /* reflectivity weight */ miScalar bump; /* bump mapping weight */ miScalar u_unit; /* epsilon dist in tex */ miScalar v_unit; /* space, for bump grad*/ miScalar u_wrap; /* u_unit if u+u_unit */ miScalar v_wrap; /* is outside of [0, 1)*/ miBoolean blackwhite; /* white or black->t=0 */ } *texture; /* texture array */ int i_light; /* index of first light*/ int n_light; /* number of lights */ miTag *light; /* list of lights */ miBoolean sblur; /* static blur mode */ miScalar sblurdecay; /* sblur falloff */ miBoolean notrace; /* no refl, just env */ int i_difflight; /* index of first */ int n_difflight; /* number of lights */ miTag *difflight; /* diffuse lights */ };
If the shader is used as a shadow shader, only the diffuse and transparency components, the light list and the diffuse light list (the material is ignored if it does not list the shadow-casting light in either list), and the texture array are used. Of the texture array elements, only map, mask, comp, blend, diffuse, and transp are used. All other fields are ignored in shadow shader mode.
The shader assumes that there are enough texture coordinates and bump basis vectors stored in the state to satisfy all space parameters. That is, if there the largest space parameter is n, there must be n+1 texture coordinates. No bump basis vectors are required for bump mapping, they are computed on the fly.
As described in the ``Writing Shaders'' chapter, every array appears in the C structure as two integers giving the index of the first element and the number of elements, and the array itself, with one member regardless of the true array size. Arrays are indexed with code like
for (n=0; n < paras->n_array; n++) do_something(paras->array[paras->i_array + n]);
In the rest of this chapter, the array support integers prefixed with i_ and n_ follow these rules and are not described explicitly. This is a list of all material shader parameters:
(see texture shader) This shader implements 2D textures. It works by calculating the texture coordinate and looking up an image texture. Standard SOFTIMAGE 2D textures are always evaluated in two stages, the first being a procedural texture shader, and the second being an image file. This shader implements the first stage. It can perform various cropping, scaling, rotation, and swapping operations. This is the .mi scene file declaration:
declare "soft_color" ( color texture "texture", integer "repu", integer "repv", boolean "altu", boolean "altv", boolean "swap", scalar "minu", scalar "maxu", scalar "minv", scalar "maxv", transform "transform", boolean "u_torus", boolean "v_torus", integer "method" )
The corresponding C structure is:
struct soft_color { miTag texture; /* texture shader */ miInteger repu, repv; /* repetition, >= 1 */ miBoolean altu, altv; /* flip alternates */ miBoolean swap; /* swap U and V coords */ miScalar minu, maxu; /* horizontal cropping */ miScalar minv, maxv; /* vertical cropping */ miMatrix transform; /* transformation */ miBoolean u_torus; /* map is cyl/spherical */ miBoolean v_torus; /* wrap V (patch only) */ miInteger method; /* 0..5=XY, YZ, XZ, UV, */ /* cyl/sphere, UV wrap */ };
(see texture shader) 3D textures, like 2D textures, are based on texture coordinates as found in state->tex. However, 3D textures use all three texture coordinates X, Y, and Z, and compute the texture based on these coordinates without referring to a texture image. Three types of textures are supported: cloud, wood, and marble. Here is the .mi scene file declaration:
declare "soft_color_3d" ( integer "seq", integer "type", scalar "spacing", scalar "angle", scalar "strength", scalar "power", integer "iteration", scalar "weight1", scalar "weight2", scalar "weight3", color "color0", color "color1", color "color2", color "color3", color "color4", transform "transform" )
The corresponding C structure is:
struct soft_color_3d { miInteger seq; /* unique seq. number */ miInteger type; /* marble, wood, cloud */ miScalar spacing; /* spacing (density) */ miScalar angle; /* rotation */ miScalar strength; /* amount of noise */ miScalar power; /* deformation strength */ miInteger iteration; /* polynomial order */ miScalar weight1; /* color weights */ miScalar weight2; miScalar weight3; miColor color0; /* 5-color color spread */ miColor color1; miColor color2; miColor color3; miColor color4; miMatrix transform; /* xlate,scale,rotation */ };
(see texture shader) The vertex color shader is very simple. It interprets the XYZ texture coordinate components as an RGB color, sets alpha to 1.0 and returns. Together with a translator that stores colors instead of texture coordinates for this shader, this implements vertex coloring. No lookup or other computation is required, and no parameters are accepted:
declare "soft_vertex_color" ()
(see texture shader) This is a variation of the previous shader. It exists for Softimage compatibility and is not recommended for other uses. It interprets the XYZ texture vector as an RGB color in the value range (0..255), instead of (0..1), taking each integer modulo 255. Additionally, the X component of the texture vector, divided by 256 and taken modulo 255, is used to set the alpha component of the returned color. With this trick four color components are extracted from three vector components. No lookup or other computation is done, and no parameters are accepted:
declare "soft_vertex_color_alpha" ()
(see light shader) This shader implements the infinite (directional) lights, point lights, and spot lights supported by SOFTIMAGE. The behavior is controlled by a mode parameter. Infinite lights use the light direction in the state, while point and spot lights use the origin in the state. Point and spot lights can have a distance attenuation, causing the light intensity to fall off with distance. The only difference between point lights and spot lights is that spot lights offer angle attenuation, which implements the spot effect by emitting the lights along a spot direction axis with a programmable falloff depending on the angle to that axis. Spot lights do not use the direction in the state as a spot direction axis.
This is the .mi scene file declaration:
declare "soft_light" ( integer "mode", color "color", boolean "shadow", scalar "factor", boolean "atten", scalar "start", scalar "stop", vector "direction", scalar "cone", scalar "spread" )
The corresponding C structure is:
struct soft_light { miInteger mode; /* 0=inf,1=point,2=spot */ miColor color; /* color of light source*/ miBoolean shadow; /* light casts shadows */ miScalar factor; /* penetrate opaque objs*/ /* --- point/spot only: */ miBoolean atten; /* distance attenuation */ miScalar start, stop; /* if atten, dist range */ /* --- spot only: */ miVector direction; /* spot direction */ miScalar cone; /* inner solid cone */ miScalar spread; /* outer fuzzy cone */ };
The displacement shader is called once for every vertex generated by surface tesselation, and returns a value that specifies how far the vertex should be translated along its normal. The displacement shader derives this value from one or more textures, using a texture lookup much like the soft_material material shader. The scalar return value is derived from the RGBA result of the texture lookups in the same way and using the same parameters that the material shader uses to derive transparency, reflectivity, and bump intensity. Its parameters are declared in the .mi scene file as:
declare "soft_displace" ( array struct "texture" { color texture "map", integer "space", integer "comp", scalar "displace" } )
The corresponding C structure is:
struct soft_displace { int i_texture; /* index of 1st texture*/ int n_texture; /* number of textures */ struct DisTex { miTag map; /* texture file */ miInteger space; /* texture vertex space*/ miInteger comp; /* 1=alpha,2=intens */ miScalar displace; /* weight of texture */ } *texture; /* list of textures */ };
The parameters are evaluated once for each texture, and their results are added.Future versions of mental ray will replace the texture pointer with an array of size [1].
(see environment shader) Environment maps are called to evaluate the color returned by a primary or secondary ray that goes to infinity without hitting an object, or to evaluate the color of a reflected secondary ray quickly without checking for intersections with other objects. The second case is called a ``non-raytraced reflection map'' in the SOFTIMAGE Creative Environment.
This shader works by assuming a sphere of infinite radius around the entire scene. One or more textures are mapped on this sphere, so that the color lookup operates in exactly the same way as texture lookups in the material and displacement shaders. The soft_env_sphere shader accepts the same types of arguments as these two shaders. Here are the .mi scene file declarations:
declare "soft_env_sphere" ( scalar "rotate", array struct "texture" { color texture "map", integer "mask", scalar "blend" } )
The corresponding C structure is:
struct soft_env_sphere { miScalar rotate; /* global rotation */ int i_texture; /* index of 1st texture*/ int n_texture; /* number of textures */ struct EnvTex { miTag map; /* texture file */ miInteger mask; /* none, alpha, intens */ miScalar blend; /* overall blending */ } *texture; /* list of textures */ };
(see volume shader) (see fog) (see atmosphere) The fog shader is a volume shader that implements simple distance-based fog. Whenever a visible or light ray is cast, the resulting color is modified by the fog shader based on the distance the ray travelled, as found in state->dist, by fading the color towards a fog color. The camera is considered to be surrounded by spherically shaped layer of fog whose inner radius is the start distance and whose outer layer is the end distance. The attenuation is a linear function of the distance traveled through this fog. This is the .mi scene file declaration:
declare "soft_fog" ( scalar "start", scalar "stop", scalar "rate", color "transmit", boolean "lightrays" )
The corresponding C structure is:
struct soft_fog { miScalar start, stop; miScalar rate; miColor transmit; miBoolean lightrays; };
(see volume shader) (see fog) (see atmosphere) This shader attempts to emulate the SOFTIMAGE layered fog shader while trying to avoid its problems. A layer of fog with a vertical extent in world space is simulated. The density of the fog is given by a Poisson distribution (numerically given) that is centered around half the fog layer's height, and drops to half of the maximum value at the edges. In addition to the vertical extent of the layer, the volume filled with fog can be specified by giving a start and a stop distance along the ray, which correspond to the ray entering and leaving the volume. To turn this distance clipping off, a starting distance of 0.0 and a very large ending distance such as 10000.0 should be chosen.
Note that distance clipping emulates a peculiarity of the SOFTIMAGE layered-fog shader: it only works correctly for primary rays; secondary rays such as reflected or refracted rays are treated as if they originated at the camera. The immediate effect is that, for start distances greater than 0.0, the first segment of the length as given by the start parameter of secondary rays is not affected by fog, even if the ray originates in the middle of the fog layer.
Here is the .mi scene file declaration:
declare "soft_layered_fog" ( scalar "start", scalar "stop", scalar "base", scalar "thickness", scalar "density", color "fogcolor", boolean "lightrays" )
The corresponding C structure is:
struct soft_layered_fog { miScalar start, stop; miScalar base; miScalar thickness; miScalar density; miColor fogcolor; miBoolean lightrays; };
(see lens shader) This lens shader implements depth of field by defining a focus plane parallel to the viewing plane, and a lens size as a radius. Depth-of-field blurring is performed using adaptive distribution ray tracing, by varying the camera ray origin over a disc centered at the camera with a specified radius, while also adjusting the ray direction such that it always passes through the original point at the focus plane. The effect is that there is no difference for objects at the focus plane, but objects closer or farther away are seen at jittered angles. Adaptive sampling is used to anti-alias the result by taking multiple samples for such points. The sample locations and directions are chosen using a Monte Carlo or Quasi-Monte Carlo algorithm, depending on the -mc or -qmc command-line options. The .mi scene file declaration is:
declare "lens_depth_of_field" ( scalar "plane", scalar "radius" )
The corresponding C structure is:
struct lens_depth_of_field { miScalar plane; miScalar radius; };
(see output shader) This output shader implements depth of field by defining a a near and a far focus plane parallel to the viewing plane, and a lens size as a radius. All objects between the focus planes are in focus; objects outside this range are blurred. Unlike lens_depth_of_field, this shader computes the depth-of-field effect as a postprocessing step, using information collected during rendering. The shader must be installed in the view using an output statement, listed before the output statement that writes the image to a file:
output "z,rgba" "out_depth_of_field" (...)
The .mi scene file declaration is:
declare "out_depth_of_field" ( scalar "near", scalar "far", scalar "radius", integer "max", scalar "infinity" )
The corresponding C structure is:
struct out_depth_of_field { miScalar near; miScalar far; miScalar radius; miInteger max; miScalar infinity; };
(see shadow shader) This shader is obsolete. mental ray 1.8 and higher use the material shader as shadow shader, which avoids the need to duplicate the texture parameter block for a separate shadow shader. The shadow shader still exists for backwards compatibility reasons, in order to be able to read .mi scene files created before the change. It is strongly recommended to not use this shader in new develeopments.
The name soft_shadow indicates a SOFTIMAGE shadow shader and should not be confused with a mechanism generating soft shadows.
The parameter declaration in the .mi scene file and the C structure are identical to the parameter declarations of the soft_material shader. The soft_shadow shader does nothing but call soft_material.
(see light shader) This shader has been replaced with the soft_light shader described above. It only exists for backwards compatibility with old .mi scene files. It has a declaration and a C data structure that differs slightly in layout from the parameter declaration of soft_light; the shader itself copies the parameter structure, selects an appropriate mode, and calls soft_light. The declaration in .mi scene files is:
declare "soft_infinite" ( color "color", vector "null", boolean "shadow", scalar "factor" )
The corresponding C structure is:
struct soft_infinite { miColor color; /* color of light source */ miVector null; /* spot has dir vector here*/ miBoolean shadow; /* light casts shadows */ miScalar factor; /* penetrate opaque objects*/ };
For a description of these parameters, see soft_light.
(see light shader) (see point light) This shader has also been replaced with the soft_light shader. It only exists for backwards compatibility with old .mi scene files. It has a declaration and a C data structure that differs slightly in layout from the parameter declaration of soft_light; the shader itself copies the parameter structure, selects an appropriate mode, and calls soft_light. The declaration in .mi scene files is:
declare "soft_point" ( color "color", vector "null", boolean "shadow", scalar "factor", boolean "atten", scalar "start", scalar "stop" )
The corresponding C structure is:
struct soft_point { miColor color; /* color of light source */ miVector null; /* spot has dir vec here */ miBoolean shadow; /* light casts shadows */ miScalar factor; /* penetrate opaque objs */ miBoolean atten; /* distance attenuation */ miScalar start, stop; /* if atten, dist range */ };
For a description of these parameters, see soft_light.
(see light shader) (see point light) This is yet another light shader that has been replaced with the soft_light shader. It is also obsolete and only exists for backwards compatibility with old .mi scene files. It has a declaration and a C data structure that differs slightly in layout from the parameter declaration of soft_light; the shader itself copies the parameter structure, selects an appropriate mode, and calls soft_light. The declaration in .mi scene files is:
declare "soft_spot" ( color "color", vector "direction", boolean "shadow", scalar "factor", boolean "atten", scalar "start", scalar "stop", scalar "cone", scalar "spread" )
The corresponding C structure is:
struct soft_spot { miColor color; /* color of light source */ miVector direction; /* spot direction */ miBoolean shadow; /* light casts shadows */ miScalar factor; /* penetrate opaque objs */ miBoolean atten; /* distance attenuation */ miScalar start, stop; /* if atten, dist range */ miScalar cone; /* inner solid cone */ miScalar spread; /* outer fuzzy cone */ };
For a description of these parameters, see soft_light.
Seven shaders implement Wavefront compatibility. The material shader is controlled by a illumination mode parameter that controls which shading model is desired. Note that Wavefront shader do not deal with the alpha channel; all alpha components are ignored and none are computed, with one exception: the mi_wave_material shader always returns an alpha of 1.0. This makes sure that a legal alpha channel is written to image files that contain an alpha channel.
name operation
mi_wave_material material shader: all shading models mi_wave_scalar_texture scalar texture shader mi_wave_vector_texture vector texture shader mi_wave_color_texture color texture shader mi_wave_light light shader: point, infinite, spot mi_wave_shadow shadow shader mi_wave_reflection_map environment shader
If any of these shaders is used in a .mi scene file, the scene file must include the wavefront.mi header file that contains the shader declarations, using a $include command (see include command) . The C structures are declared in a file mi_wavefront.h, to be included in the C source file of custom shaders making direct calls to Wavefront shaders.
(see material shader) (see Wavefront shaders) The material shader implements the Wavefront shading models 0 through 9. Illumination model 0 gives the surface a uniform color equal to the diffuse color. The illumination of a surface with this material is computed according to
Model 1 is purely diffuse. The illumination of a surface with this material is computed according to
Model 2 includes both diffuse and specular components. The illumination of a surface with this material is computed using Phong shading according to
In addition to diffuse and specular components (Phong shading), model 3 includes the illumination contributed by reflections or reflection mapping. The illumination of a surface with this material is computed according to
Model 4 is similar to model 3 but is more suitable for a simulation of glass where the transparency is nearly 1.0, but the highlights should not be affected (should not fade out, as they would with model 3). The illumination of a surface with this material is computed according to
Model 5 is similar to model 3 but with Fresnel calculation of reflected light. The illumination of a surface with this material is computed according to
In addition to diffuse, specular and reflection contributions, model 6 includes refracted light similar to the calculation used by Whitted. Note that the distance the ray travels through the material is not taken into account. See also [Whitted 80]. The illumination of a surface with this material is computed according to
Model 7 is the same as model 6 but with Fresnel calculation of reflected and refracted color. The illumination of a surface with this material is computed according to
Models 8 and 9 are identical to 3 and 4, respectively, except that the contribution from reflected illumination can only come from a reflection map, not from reflected rays. This is useful to improve performance. (see material shader)
The material shader has the following .mi scene file declaration:
declare "wave_material" ( integer "illum", color "ambient", color "diffuse", color "specular", color "transmit", scalar "dissolve", scalar "ns", scalar "ni", color texture "ambient_map", color texture "diffuse_map", color texture "specular_map", scalar texture "dissolve_map", scalar texture "ns_map", vector texture "bump_map", array light "lights", boolean "use_reflectivity", color "reflect" )
The corresponding C structure is:
struct wave_material { miInteger illum; miColor ambient; miColor diffuse; miColor specular; miColor transmit; miScalar dissolve; miScalar ns; miScalar ni; miTag ambient_map; miTag diffuse_map; miTag specular_map; miTag dissolve_map; miTag ns_map; miTag bump_map; int i_lights; int n_lights; miTag *lights; miBoolean use_reflectivity; miColor reflect; };
If one of the texture maps is defined, the shader requires exactly one set of texture coordinates, plus a set of bump basis vectors if a bump map, in the state.
(see texture shader) This shader implements a texture lookup function for scalar textures. Scalar textures are used for mapping the dissolve and shinyness parameters in the material. The shader requires a scalar texture image, it does not extract alpha or intensity from a color image. This is the .mi scene file declaration:
declare "wave_scalar_texture" ( scalar texture "tex", vector "origin", vector "scale", scalar "base", scalar "gain" )
The corresponding C structure is:
struct wave_scalar_texture { miTag tex; miVector origin; miVector scale; miScalar base; miScalar gain; };
(see texture shader) This shader implements a texture lookup function for vector textures. Vector textures are used for bump mapping. This shader is similar to mi_wave_scalar_texture, except that it deals with 3D vectors and not with scalars. This is the .mi scene file declaration:
declare "wave_vector_texture" ( vector texture "tex", vector "origin", vector "scale", vector "base", vector "gain" )
The corresponding C structure is:
struct wave_vector_texture { miTag tex; miVector origin; miVector scale; miScalar base; miScalar gain; };
(see texture shader) This shader implements a texture lookup function for color textures. Color textures are used for ambient, diffuse, and specular color mapping. This shader is similar to mi_wave_scalar_texture, except that it deals with RGB colors and not with scalars. This is the .mi scene file declaration:
declare "wave_color_texture" ( color texture "tex", color "origin", color "scale", color "base", color "gain" )
The corresponding C structure is:
struct wave_color_texture { miTag tex; miVector origin; miVector scale; miScalar base; miScalar gain; };
(see light shader) This shader implements Wavefront's omnidirectional, directional, and infinite light sources. In mental ray terminology, these are called point lights, spot lights, and directional lights. Point and spot lights may have distance attenuation; spot lights have angle attenuation. Various kinds of falloff are available.
This is the .mi scene file declaration:
declare "wave_light" ( color "color", vector "dir", boolean "dist_linear", scalar "dist_start", scalar "dist_end", boolean "dist_inverse", scalar "dist_power", boolean "angle_linear", scalar "angle_outer", scalar "angle_inner", boolean "angle_cosine", scalar "angle_power" )
The corresponding C structure is:
struct wave_light { miColor color; miVector dir; miBoolean dist_linear; miScalar dist_start; miScalar dist_end; miBoolean dist_inverse; miScalar dist_power; miBoolean angle_linear; miScalar angle_outer; miScalar angle_inner; miBoolean angle_cosine; miScalar angle_power; };
(see shadow shader) Shadow shaders are called when a shadow ray intersects an object occluding the light source as seen from the illuminated point. The mi_wave_shadow shader reduces the intensity of the light color based on the dissolve value of the object, which can be either constant or texture-mapped. The object color is not taken into account. Here are the .mi scene file declarations:
declare "wave_shadow" ( scalar "dissolve", color texture "dissolve_map" )
The corresponding C structure is:
struct wave_shadow { miScalar dissolve; miTag dissolve_map; };
The parameters are normally duplicates of the respective parameters of the mi_wave_material shader. Unlike the SOFTIMAGE shaders, the Wavefront material shader does not double as shadow shader.
Environment maps are called to evaluate the color returned by a primary or secondary ray that goes to infinity without hitting an object, or to evaluate the color of a reflected secondary ray quickly without checking for intersections with other objects. The Wavefront environment shader assumes that a single texture is mapped on the inside of an infinite sphere enclosing the scene. It looks up a color on the texture map based on the direction of the ray. This is the .mi scene file declaration:
declare "wave_reflection_map" ( color texture "tex", transform "transform" )
The corresponding C structure is:
struct wave_reflection_map { miTag tex; miMatrix transform; };
SOFTIMAGE Material Implementation
The Softimage material shader is a very complex shader that handles object inside/outside calculations, texture compositing, light illumination, secondary rays, and static blur, and is also usable as a shadow shader. This chapter explains the internals of this shader, to allow shader writers to write modified versions. For a general description of the shader parameters, see above.
The functions described in this chapter are all callable by external shaders. Note that they all rely on a material structure that is either identical to struct soft_material, or begins with a structure identical to struct soft_material.
Here is the actual source code of the soft_material shader mainline:
miBoolean soft_material( register miColor *result, register miState *state, struct soft_material *paras) { struct soft_material m; /* work area */ miScalar ior_in,ior_out; /* refr index*/ if (state->type == miRAY_SHADOW) { if (!mi_mtl_is_casting_shadow(state, paras)) return(miFALSE); } else mi_mtl_refraction_index(state, paras, &ior_in, &ior_out); m = *paras; mi_mtl_textures(state, &m, paras, &state->normal, &state->dot_nd); mi_mtl_static_blur(state, &m); if (state->type == miRAY_SHADOW) return(mi_mtl_compute_shadow(result, &m)); mi_mtl_illumination(result, state, &m, paras, ior_in, ior_out); mi_mtl_reflection(result, state, &m); mi_mtl_refraction(result, state, &m, ior_in, ior_out); return(miTRUE); }
This shader is based on a copy m of the material parameters paras. This copy is modified by certain functions, particularly mi_mtl_textures, avoiding a large number of pointer arguments such as ambient or transparency. Note that only those parts of the paras structure are copied that are defined by struct soft_material; this does not include the array contents, which is the reason why some functions have both a paras and an m argument. The mi_mtl_illumination function, for example, needs access to both the light array paras->lights and the ambient, diffuse, and specular colors in m, as calculated by mi_mtl_textures. This shader also checks twice if it is called as a shadow shader, by checking state->type, to shortcut certain operations only needed in material shaders.
The functions used by soft_material are:
miBoolean mi_mtl_is_casting_shadow( register miState *state, register struct soft_material *paras) { register int num; for (num=0; num < paras->n_light; num++) if (state->instance == paras->light[paras->i_light + num]) return(miTRUE); for (num=0; num < paras->n_difflight; num++) if (state->instance == paras->difflight[paras->i_difflight + num]) return(miTRUE); return(miFALSE); }
This function is used only in the shadow shader case. It checks whether the light casting the shadow is in the material shader's light list (the shadow shader gets the same parameters as the material shader because the shadow soft_material statement in the .mi file has an empty parameter list).
void mi_mtl_refraction_index( miState *state, struct soft_material *paras, miScalar *ior_in, miScalar *ior_out) { register int num; register miState *s, *s_in; num = state->type == miRAY_REFRACT || state->type == miRAY_TRANSPARENT; for (s_in=0, s=state->parent; s; s=s->parent) { if ((s->type == miRAY_REFRACT || s->type == miRAY_TRANSPARENT) && s->shader == state->shader) { num++; if (!s_in) s_in = s->parent; } } if (num & 1) { *ior_in = paras->ior; *ior_out = s_in && s_in->ior != 0 ? s_in->ior : 1; state->refraction_volume = s_in ? s_in->refraction_volume : state->camera->volume; } else { *ior_out = paras->ior; *ior_in = state->parent && state->parent->ior != 0 ? state->parent->ior : 1; if (!state->refraction_volume) state->refraction_volume = state->volume; } state->ior = *ior_out; }
This function computes the indices of refraction on the incoming and outgoing ray, and sets the appropriate volume shader in the state. It operates by following the state parent links all the way back to the primary ray, and counts the number of times this shader was called before. If it was called an odd number of times, the ray is exiting the object, otherwise it is entering. For example, on the back side of a sphere, this function will find that the material has been called once before (for the front side); 1 is an odd number so this ray must be exiting. Materials are distinguished by their parameters. Note that this implements a heuristic; mental ray operates with intersections, not volumes, and allows rendering non-volume objects such as SOFTIMAGE ``grids'' and collections of polygons with different materials where inside/outside calculations cannot be performed meaningfully.
void mi_mtl_textures( miState *state, /* ray state */ struct soft_material *m, /* ret. new paras */ struct soft_material *paras, /* shader paras */ miVector *normal, /* bumpmapped n */ miScalar *dot_nd, /* n <dot> dir */ { *normal = state->normal; *dot_nd = state->dot_nd; for (n=0; n < paras->n_texture; n++) { tex = ¶s->texture[paras->i_texture + n]; if (!mi_lookup_color_texture (&result, state, (miTag)tex->map, &state->tex_list[tex->space]) || result.a < -0.001) continue; { calculate blend and mask } { calculate m->diffuse } { calculate m->transp } if (state->type == miRAY_SHADOW) continue; { calculate m->ambient } { calculate m->specular } { calculate m->reflect } if (tex->bump != 0 && !state->contour) { { take color sample u_unit to the side } { take color sample v_unit above } { calculate bump basis vectors } { perturb *normal according to diffs } mi_vector_normalize(normal); *dot_nd = mi_vector_dot(normal, &state->dir); } } { multiply m->ambient by m->ambience } }
This function looks up textures and applies the results to the copy m of the material parameters. Note that the light loop uses paras, not m, because m does not contain a copy of the arrays. The result of the texture lookup is checked for negative alphas to provide backwards compatibility to texture shaders written for version 1.8 of mental ray. The actual calculations are given as pseudocode enclosed in braces; the actual sorce code re-implements algorithms developed by SOFTIMAGE.
miBoolean mi_mtl_compute_shadow( miColor *result, struct soft_material *m)
This function multiplies the result color by a color computed from m->diffuse and m->transp, and returns miTRUE if the resulting color is not black.
void mi_mtl_static_blur( miState *state, /* ray tracer state */ struct soft_material *m) /* textured mtl paras*/
If m->sblur is miTRUE, this function modifies m->transp according to state->dir, state->normal, and m->sblurdecay.
void mi_mtl_illumination( register miColor *result, /* ret.illum color */ miState *state, /* ray state */ struct soft_material *m,*paras)/* mtl paras */ { int n; /* light counter */ register miTag *light; /* current light */ miColor col; /* light color */ miVector dir; /* dir toward light*/ miScalar dot_nl; /* normal <dot> dir*/ miScalar ns; /* specular factor */ if (m->transp >= 1) { result->r = result->g = result->b = result->a = 0; return; } if (m->mode == 0 || state->contour) { *result = m->diffuse; result->a = 1; return; } *result = m->ambient; for (n=0; n < paras->n_light; n++) { light = ¶s->light[paras->i_light + n]; if (mi_trace_light(&col, &dir, &dot_nl, state, (char *)*light)) { result->r += dot_nl * m->diffuse.r * col.r; result->g += dot_nl * m->diffuse.g * col.g; result->b += dot_nl * m->diffuse.b * col.b; if (m->mode == 2) { ns = mi_phong_specular(m->shiny, state, &dir); result->r += ns * m->specular.r * col.r; result->g += ns * m->specular.g * col.g; result->b += ns * m->specular.b * col.b; } if (m->mode == 3) { ns = mi_blinn_specular(m->shiny, state, &dir); result->r += ns * m->specular.r * col.r; result->g += ns * m->specular.g * col.g; result->b += ns * m->specular.b * col.b; } } } for (n=0; n < paras->n_diff_light; n++) { light = ¶s->diff_light[paras->i_diff_light + n]; if (mi_trace_light(&col, &dir, &dot_nl, state, (char *)*light)) { result->r += dot_nl * m->diffuse.r * col.r; result->g += dot_nl * m->diffuse.g * col.g; result->b += dot_nl * m->diffuse.b * col.b; } } result->a = 1; }
This function calculates a result color based on the ambient, diffuse, and specular colors computed by mi_mtl_texture. It is a straightforward implementation of standard Lambert, Phong, and Blinn shading. The alpha of the resulting color is set to 1, effectively making the material opaque. If refraction rays are cast, the alpha will be reduced by mi_mtl_refraction later.
void mi_mtl_reflection( register miColor *result, /* ret. illum color */ miState *state, /* ray tracer state */ struct soft_material *m) /* mtl paras */ { miColor color; /* reflect ray color*/ miVector dir; /* dir towards light*/ if (m->reflect > 0) { miScalar f = 1 - m->reflect; result->r *= f; result->g *= f; result->b *= f; if (!state->contour && state->reflection_level < state->options->reflection_depth && state->reflection_level + state->refraction_level < state->options->trace_depth) { mi_reflection_dir(&dir, state); if (!m->notrace && mi_trace_reflection (&color, state, &dir) || mi_trace_environment(&color, state, &dir)) { result->r += m->reflect * color.r; result->g += m->reflect * color.g; result->b += m->reflect * color.b; } } } }
If the material is reflective, and mental ray is not in contour rendering mode, this shader casts a reflection ray, and merges the result from that ray with the result color. The alpha value is not changed.
void mi_mtl_refraction( register miColor *result, /* ret. illum color */ miState *state, /* ray tracer state */ struct soft_material *m, /* mtl paras */ double ior_in, /* refraction index */ double ior_out; { miColor color; /* reflect ray color*/ miVector dir; /* dir towards light*/ if (m->transp > 0) { miScalar f = 1 - m->transp; result->r *= f; result->g *= f; result->b *= f; result->a *= f; if (state->contour) return; state->refraction_level--; if (mi_refraction_dir(&dir, state, ior_in, ior_out)) { miTag env_save = state->environment; state->environment = 0; ok = ior_in == ior_out ? mi_trace_transparent(&color, state) : mi_trace_refraction (&color, state, &dir); state->environment = env_save; } else { mi_reflection_dir(&dir, state); ok = m->notrace ? mi_trace_environment(&color, state, &dir) : mi_trace_reflection (&color, state, &dir); } if (ok) { result->r += m->transp * color.r; result->g += m->transp * color.g; result->b += m->transp * color.b; result->a += m->transp * color.a; } } }
This function casts transparency or refraction rays if the material is transparent. In this case, the material alpha is reduced. If the incoming and outgoing indices of refractions are the same, the ray direction does not change and a transparency ray can be used; otherwise a refraction ray is used. Transparency rays are more efficient and can be performed by the scanline algorithm if enabled. If the index of refraction (less than 1.0) causes the ray to be cast on the same side as the incoming ray, a reflection ray is used instead. The environment state variable is cleared to prevent mental ray from sampling the environment if the refracted ray does not intersect with another object (which would be the normal behavior). Note that the indices of refraction are passed as doubles to allow shaders written in classic K&R C to call this function.