Shader parameter_volume

Click on the filename to display or download the file.

parameter_volume.mi
declare shader 
    color "parameter_volume" ( 
	color "color" default 1 1 1, 
	shader "density_shader", 
	scalar "unit_density" default 1, 
	scalar "march_increment" default 0.1, 
	array light "lights" ) 
    version 1 
    apply volume 
end declare 

parameter_volume.c
#include "shader.h" 
#include "miaux.h" 
 
struct parameter_volume { 
    miColor color; 
    miTag density_shader; 
    miScalar unit_density; 
    miScalar march_increment; 
    int     i_light; 
    int     n_light;  
    miTag   light[1]; 
}; 
 
DLLEXPORT 
int parameter_volume_version(void) { return 1; } 
 
DLLEXPORT 
miBoolean parameter_volume (  
    miColor *result, miState *state, struct parameter_volume *params  ) 
{ 
    miScalar unit_density, march_increment, density; 
    miTag density_shader, *light; 
    int light_count; 
 
    if (state->type == miRAY_LIGHT) 
        return miTRUE; 
 
    density_shader = *mi_eval_tag(&params->density_shader); 
    unit_density = *mi_eval_scalar(&params->unit_density); 
    march_increment = *mi_eval_scalar(&params->march_increment); 
    miaux_light_array(&light, &light_count, state, 
                      &params->i_light, &params->n_light, params->light); 
 
    if (state->type == miRAY_SHADOW) { 
        miScalar occlusion = miaux_fractional_shader_occlusion_at_point ( 
            state, &state->org, &state->dir, state->dist, 
            density_shader, unit_density, march_increment); 
        miaux_scale_color(result, 1.0 - occlusion); 
    } else { 
        miColor *color = mi_eval_color(&params->color); 
        miScalar distance; 
        miColor volume_color = {0,0,0,0}, light_color, point_color; 
        miVector original_point = state->point; 
        void* original_state_pri = state->pri; 
        state->pri = NULL; 
 
        for (distance = 0; distance <= state->dist; distance += march_increment) { 
            miVector march_point; 
            miaux_march_point(&march_point, state, distance); 
            state->point = march_point; 
            mi_call_shader_x((miColor*)&density,  
                             miSHADER_MATERIAL, state, density_shader, NULL); 
            if (density > 0) { 
                density *= unit_density * march_increment; 
                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->point = original_point; 
        state->pri = original_state_pri; 
    } 
    return miTRUE; 
} 

parameter_volume_util.c
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; 
} 
 
miScalar miaux_fractional_shader_occlusion_at_point( 
    miState *state, miVector *start_point, miVector *direction,  
    miScalar total_distance, miTag density_shader, 
    miScalar unit_density, miScalar march_increment) 
{ 
    miScalar density, distance, occlusion = 0.0; 
    miVector march_point; 
    miVector original_point = state->point; 
    mi_vector_normalize(direction); 
    for (distance = 0; distance <= total_distance; distance += march_increment) { 
	miaux_point_along_vector(&march_point, start_point, direction, distance); 
	state->point = march_point; 
	mi_call_shader_x((miColor*)&density, miSHADER_MATERIAL, state,  
			 density_shader, NULL); 
	occlusion += density * unit_density * march_increment; 
	if (occlusion >= 1.0) { 
	    occlusion = 1.0; 
	    break; 
	} 
    } 
    state->point = original_point; 
    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; 
} 
 
void miaux_scale_color(miColor *result, miScalar scale) 
{ 
    result->r *= scale; 
    result->g *= scale; 
    result->b *= scale; 
} 
 
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:55