Photon emitter shaders are used in the photon tracing phase to control the emission of photons from the light sources. There exists a number of built-in photon emitters that handle the following types of light sources:
Unless there are good reasons, these light sources should be used since they are well optimized. This is particularly true for the point light and sphere light which use a projection map to limit the emission of photons to the directions in which caustic generating objects are found. The appropriate built-in photon emitters are automatically applied if no photon emitter is specified in the light source definition.
If more complex light sources are needed, it can be necessary to write a specialized shader. For example, this could be necessary for a spot light that should support intensity fading near the edges of the cone. Note that the light emitter shader is not called if the light has zero energy; such lights are ignored by mental ray during photon tracing.
An example of a simple point light that emits photons uniformly in all directions around the current point is given in the following shader3.1. The shader receives information about the light source from state - > light_instance.
#include <stdio.h> #include <math.h> #include "shader.h" int point_emitter_version() {return(1);} void point_emitter_init( miState *state, void *p, miBoolean *inst_init_req) { miTag light_tag; miMatrix *T; if (!p) *inst_init_req = miTRUE; else { miVector org, *torg; torg = mi_mem_allocate(sizeof(miVector)); mi_query(miQ_INST_ITEM, state, state->light_instance, &light_tag); mi_query(miQ_INST_LOCAL_TO_GLOBAL, state, state->light_instance, &T); mi_query(miQ_LIGHT_ORIGIN, state, light_tag, &org); mi_point_transform(torg, &org, *T); state->shader->user.p = torg; } } void point_emitter_exit( miState *state, void *p) { if (state->shader->user.p && p) { mi_mem_release(state->shader->user.p); state->shader->user.p = NULL; } } miBoolean point_emitter( miColor *energy, miState *state, void *p) { state->org = *(miVector *)state->shader->user.p; do mi_scattering_dir_diffuse(&state->dir, state); while ((state->dir.x * state->dir.x + state->dir.y * state->dir.y + state->dir.z * state->dir.z) > 1.0); mi_vector_normalize(&state->dir); mi_photon_light(energy, state); return(miTRUE); }
This shader does not take any parameters. Instead it extracts all information about the light source with mi_query. This shader can be attached to a light definition using the photon statement. Note the choice of direction using mi_scattering_dir_diffuse and rejection sampling: instead of limiting the computed directions to points in a circle, rectangular directions are computed and rejected if they fall outside the circle. This is more efficient than computing polar coordinates, adjusting for uniform density, and converting to rectangular coordinates. The org and dir or any other ray state variables are undefined when the shader is called, the shader must come up with its own directions.
If a photon emitter shader returns miFALSE, photon emission from the current light source is aborted at that point and no more photons are cast from this light source. It is recommended that photon emitter shaders return miTRUE only if they called mi_photon_light because otherwise mental ray will keep calling the shader for a long time without ever storing a photon.