By definition, transparency is the physical property of allowing light to pass through a material. So, before I start, we need to examine this function.
miBoolean mi_trace_transparent( miColor *result, miState *state)
From Mental Ray online manual
This function casts a ray from state→dir to direction. It returns miFALSE if the trace depth has been exhausted or if the hit object has disabled refraction receiving. If no intersection is found, the optional environment shader is called. It also works when ray tracing is turned off, and considers visible as well as trace objects.
From Writing mental ray® Shaders,
The API library function mi_trace_transparent sends a ray in the same direction and stores the resulting color in result. Note that this is a potentially recursive shader call—if the ray strikes another instance with a material that contains this transparency shader, then mi_trace_transparent will be called in it, and so on.
Final Image |
MI Source
C Source: Basic
C Source: Optimized
declare shader color "transparent" ( color "base" default 1 1 1, color "transparency" default 0 0 0 ) apply material end declare
C Source: Basic
#include "shader.h" struct transparent { miColor base; miColor transparency; }; miBoolean transparent(miColor *result, miState *state, struct transparent *params) { miColor opacity; miColor *base = mi_eval_color(¶ms->base); miColor *transparency = mi_eval_color(¶ms->transparency); mi_trace_transparent(result, state); opacity.r = 1 - transparency->r; opacity.g = 1 - transparency->g; opacity.b = 1 - transparency->b; opacity.a = 1 - transparency->a; result->r = result->r * transparency->r + base->r * opacity.r; result->g = result->g * transparency->g + base->g * opacity.g; result->b = result->b * transparency->b + base->b * opacity.b; return miTRUE; }
C Source: Optimized
#include "shader.h" struct transparent { miColor base; miColor transparency; }; miBoolean transparent(miColor *result, miState *state, struct transparent *params) { miColor *transparency = mi_eval_color(¶ms->transparency); if (transparency->r == 0 && transparency->g == 0 && transparency->b == 0) { *result = *mi_eval_color(¶ms->base); } else { if (!(transparency->r == 1 && transparency->g == 1 && transparency->b == 1 && transparency->a == 1)) { miColor *base = mi_eval_color(¶ms->base); miColor opacity; mi_trace_transparent(result, state); opacity.r = 1 - transparency->r; opacity.g = 1 - transparency->g; opacity.b = 1 - transparency->b; opacity.a = 1 - transparency->a; mi_opacity_set(state, &opacity); result->r = result->r * transparency->r + base->r * opacity.r; result->g = result->g * transparency->g + base->g * opacity.g; result->b = result->b * transparency->b + base->b * opacity.b; } } return miTRUE; }
Notes
What the optimized code is doing is that for every point P, if the transparency value equals to 0, just evaluate the color. And if the transparency values are not equal to 1, run the trace function.
Exercises
1. Write an all channel equal boolean function. Two parameters, input color C and input scalar V. Compare C.r, C.g, C.b to V, if equal, return miTRUE.
2. Write an invert auxiliary function. One parameter, input color.
3. Write a blend channel function. Compared to blend color, this function takes *result, and use miColor channels as factor ie. transparency.
4. Rewrite the transparency shader with the auxiliary functions.
0 comments:
Post a Comment