Click on the filename to display or download the file.
illuminated_volume.mi
declare shader
color "illuminated_volume" (
color "color" default 1 1 1 1,
vector "center" default 0 0 0,
scalar "radius" default 1,
scalar "unit_density" default 1,
scalar "march_increment" default 0.1,
array light "lights" )
version 1
apply volume
end declare
illuminated_volume.c
#include "shader.h"
#include "miaux.h"
struct illuminated_volume {
miColor color;
miVector center;
miScalar radius;
miScalar unit_density;
miScalar march_increment;
int i_light;
int n_light;
miTag light[1];
};
DLLEXPORT
int illuminated_volume_version(void) { return 1; }
DLLEXPORT
miBoolean illuminated_volume (
miColor *result, miState *state, struct illuminated_volume *params )
{
miScalar radius, unit_density, march_increment, density, distance;
miVector *center, internal_center, march_point;
int light_count;
miTag *light;
if (state->type == miRAY_LIGHT)
return miTRUE;
center = mi_eval_vector(¶ms->center);
radius = *mi_eval_scalar(¶ms->radius);
unit_density = *mi_eval_scalar(¶ms->unit_density);
march_increment = *mi_eval_scalar(¶ms->march_increment);
mi_point_from_object(state, &internal_center, center);
if (state->type == miRAY_SHADOW) {
miScalar occlusion = miaux_fractional_occlusion_at_point (
&state->org, &state->dir, state->dist,
&internal_center, radius, unit_density, march_increment);
miaux_scale_color(result, 1.0 - occlusion);
} else {
miColor *color = mi_eval_color(¶ms->color);
miColor volume_color = {0,0,0,0}, light_color, point_color;
void* original_state_pri = state->pri;
state->pri = NULL;
miaux_light_array(&light, &light_count, state,
¶ms->i_light, ¶ms->n_light, params->light);
for (distance = 0; distance <= state->dist; distance += march_increment) {
miaux_march_point(&march_point, state, distance);
density = miaux_threshold_density(
&march_point, &internal_center, radius,
unit_density, march_increment);
if (density > 0.0) {
miaux_total_light_at_point(
&light_color, &march_point, state, light, light_count);
miaux_multiply_colors(&point_color, color, &light_color);
miaux_add_transparent_color(&volume_color, &point_color, density);
}
if (volume_color.a == 1.0)
break;
}
miaux_alpha_blend_colors(result, &volume_color, result);
state->pri = original_state_pri;
}
return miTRUE;
}
illuminated_volume_util.c
miScalar miaux_fractional_occlusion_at_point(
miVector *start_point, miVector *direction,
miScalar total_distance, miVector *center, miScalar radius,
miScalar unit_density, miScalar march_increment)
{
miScalar distance, occlusion = 0.0;
miVector march_point;
mi_vector_normalize(direction);
for (distance = 0; distance <= total_distance; distance += march_increment) {
miaux_point_along_vector(&march_point, start_point, direction, distance);
occlusion += miaux_threshold_density(&march_point, center, radius,
unit_density, march_increment);
if (occlusion >= 1.0) {
occlusion = 1.0;
break;
}
}
return occlusion;
}
void miaux_point_along_vector(
miVector *result, miVector *point, miVector *direction, miScalar distance)
{
result->x = point->x + distance * direction->x;
result->y = point->y + distance * direction->y;
result->z = point->z + distance * direction->z;
}
miScalar miaux_threshold_density(
miVector *point, miVector *center, miScalar radius,
miScalar unit_density, miScalar march_increment)
{
miScalar distance = mi_vector_dist(center, point);
if (distance <= radius)
return unit_density * march_increment;
else
return 0.0;
}
void miaux_scale_color(miColor *result, miScalar scale)
{
result->r *= scale;
result->g *= scale;
result->b *= scale;
}
void miaux_light_array(miTag **lights, int *light_count, miState *state,
int *offset_param, int *count_param, miTag *lights_param)
{
int array_offset = *mi_eval_integer(offset_param);
*light_count = *mi_eval_integer(count_param);
*lights = mi_eval_tag(lights_param) + array_offset;
}
void miaux_march_point(
miVector *result, miState *state, miScalar distance)
{
miaux_point_along_vector(result, &state->org, &state->dir, distance);
}
void miaux_total_light_at_point(
miColor *result, miVector *point, miState *state,
miTag* light, int light_count)
{
miColor sum, light_color;
int i, light_sample_count;
miVector original_point = state->point;
state->point = *point;
miaux_set_channels(result, 0.0);
for (i = 0; i < light_count; i++, light++) {
miVector direction_to_light;
light_sample_count = 0;
miaux_set_channels(&sum, 0.0);
while (mi_sample_light(&light_color, &direction_to_light, NULL,
state, *light, &light_sample_count))
miaux_add_scaled_color(&sum, &light_color, 1.0);
if (light_sample_count)
miaux_add_scaled_color(result, &sum, 1/light_sample_count);
}
state->point = original_point;
}
void miaux_set_channels(miColor *c, miScalar new_value)
{
c->r = c->g = c->b = c->a = new_value;
}
void miaux_add_scaled_color(miColor *result, miColor *color, miScalar scale)
{
result->r += color->r * scale;
result->g += color->g * scale;
result->b += color->b * scale;
}
void miaux_multiply_colors(miColor *result, miColor *x, miColor *y)
{
result->r = x->r * y->r;
result->g = x->g * y->g;
result->b = x->b * y->b;
}
void miaux_add_transparent_color(
miColor *result, miColor *color, miScalar transparency)
{
miScalar new_alpha = result->a + transparency;
if (new_alpha > 1.0)
transparency = 1.0 - result->a;
result->r += color->r * transparency;
result->g += color->g * transparency;
result->b += color->b * transparency;
result->a += transparency;
}
void miaux_alpha_blend_colors(
miColor *result, miColor *foreground, miColor *background)
{
double bg_fraction = 1.0 - foreground->a;
result->r = foreground->r + background->r * bg_fraction;
result->g = foreground->g + background->g * bg_fraction;
result->b = foreground->b + background->b * bg_fraction;
}
22 April 2008 23:40:54