Shader hair_color_light

Click on the filename to display or download the file.

hair_color_light.mi
declare shader 
    color "hair_color_light" ( 
        color "ambient"   default 0 0 0, 
        color "diffuse"   default 1 1 1, 
	color "specular"  default 0 0 0, 
	scalar "exponent" default 30, 
        scalar "root_opacity" default 1, 
        scalar "tip_opacity"  default 0, 
	scalar "color_variance" default .1, 
        array light "lights" ) 
    version 1 
    apply material 
end declare 

hair_color_light.c
#include "shader.h" 
#include "miaux.h" 
 
struct hair_color_light { 
    miColor  ambient;   
    miColor  diffuse;   
    miColor  specular;  
    miScalar exponent; 
    miScalar root_opacity; 
    miScalar tip_opacity; 
    miScalar color_variance; 
    int      i_light;   
    int      n_light;   
    miTag    light[1];  
}; 
 
DLLEXPORT 
int hair_color_light_version(void) { return 1; } 
 
void hair_color_variance( 
    miColor *result, miState *state, struct hair_color_light* params) 
{ 
    miScalar maximum_variance = *mi_eval_scalar(&params->color_variance); 
    miScalar color_variance =  
        miaux_fit(state->tex_list[0].x, 0.0, 1.0,  
                  1.0 - maximum_variance, 1.0 + maximum_variance); 
    *result = *mi_eval_color(&params->diffuse); 
    miaux_scale_color(result, color_variance); 
    miaux_clamp_color(result); 
} 
 
miScalar hair_alpha(miState *state, struct hair_color_light* params) 
{ 
    return miaux_fit(state->bary[1], 0.0, 1.0, 
                     *mi_eval_scalar(&params->root_opacity), 
                     *mi_eval_scalar(&params->tip_opacity)); 
} 
 
 
miBoolean hair_shadow(miColor *result, miColor *diffuse, miScalar alpha) 
{ 
    miScalar threshold = 0.001; 
    miScalar transparency = 1.0 - alpha; 
    result->r *= miaux_shadow_breakpoint(diffuse->r, transparency, 0.2); 
    result->g *= miaux_shadow_breakpoint(diffuse->g, transparency, 0.2); 
    result->b *= miaux_shadow_breakpoint(diffuse->b, transparency, 0.2); 
    if (result->r < threshold &&  
        result->g < threshold &&  
        result->b < threshold) 
        return miFALSE; 
    else 
        return miTRUE; 
} 
 
DLLEXPORT 
miBoolean hair_color_light ( 
    miColor *result, miState *state, struct hair_color_light *params  ) 
{ 
    int i, light_count, light_sample_count; 
    miColor diffuse, sum, light_color, *specular; 
    miVector direction_toward_light, to_camera; 
    miScalar dot_nl, alpha; 
    miTag *light; 
    miVector hair_tangent = state->derivs[0]; 
    miVector original_normal = state->normal;         
 
    hair_color_variance(&diffuse, state, params); 
    alpha = hair_alpha(state, params); 
 
    if (state->type == miRAY_SHADOW) 
        return hair_shadow(result, &diffuse, alpha); 
 
    state->normal.x = state->normal.y = state->normal.z = 0.0f; 
    to_camera = state->dir; 
    mi_vector_neg(&to_camera); 
    mi_vector_normalize(&hair_tangent); 
 
    specular = mi_eval_color(&params->specular); 
    *result = *mi_eval_color(&params->ambient); 
    result->a = alpha; 
 
    miaux_light_array(&light, &light_count, state, 
                      &params->i_light, &params->n_light, params->light); 
 
    for (i = 0; i < light_count; i++, light++) { 
        miaux_set_channels(&sum, 0); 
        light_sample_count = 0; 
        while (mi_sample_light(&light_color, &direction_toward_light, &dot_nl, 
                               state, *light, &light_sample_count)) { 
            miaux_add_diffuse_hair_component( 
                &sum, &hair_tangent, &direction_toward_light,  
                &diffuse, &light_color); 
            miaux_add_specular_hair_component( 
                &sum, &hair_tangent,  &direction_toward_light, &to_camera, 
                specular, &light_color); 
        } 
        if (light_sample_count) 
            miaux_add_scaled_color(result, &sum, 1.0/light_sample_count); 
    }         
    state->normal = original_normal; 
    if (result->a < 0.999) 
        miaux_add_transparent_hair_component(result, state); 
    return miTRUE; 
} 

hair_color_light_util.c
double miaux_fit( 
    double v, double oldmin, double oldmax, double newmin, double newmax)     
{ 
    return newmin + ((v - oldmin) / (oldmax - oldmin)) * (newmax - newmin); 
} 
 
void miaux_scale_color(miColor *result, miScalar scale) 
{ 
    result->r *= scale; 
    result->g *= scale; 
    result->b *= scale; 
} 
 
void miaux_clamp_color(miColor *result) 
{ 
    result->r = miaux_clamp(result->r, 0.0, 1.0); 
    result->g = miaux_clamp(result->g, 0.0, 1.0); 
    result->b = miaux_clamp(result->b, 0.0, 1.0); 
    result->a = miaux_clamp(result->a, 0.0, 1.0); 
} 
 
double miaux_clamp(double v, double minval, double maxval) 
{ 
    return v < minval ? minval : v > maxval ? maxval : v; 
} 
 
double miaux_shadow_breakpoint ( 
    double color, double transparency, double breakpoint ) 
{ 
    if (transparency < breakpoint) 
	return miaux_fit(transparency, 0, breakpoint, 0, color); 
    else 
	return miaux_fit(transparency, breakpoint, 1, color, 1); 
} 
 
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_set_channels(miColor *c, miScalar new_value) 
{ 
    c->r = c->g = c->b = c->a = new_value; 
} 
 
void miaux_add_diffuse_hair_component( 
    miColor *result, miVector *hair_tangent, miVector *to_light, 
    miColor *diffuse, miColor *light_color) 
{ 
    miScalar diffuse_factor = 1.0 - fabs(mi_vector_dot(hair_tangent, to_light)); 
    miaux_add_diffuse_component(result, diffuse_factor, diffuse, light_color); 
} 
 
void miaux_add_diffuse_component( 
    miColor *result,  
    miScalar light_and_surface_cosine,  
    miColor *diffuse, miColor *light_color) 
{ 
    result->r += light_and_surface_cosine * diffuse->r * light_color->r; 
    result->g += light_and_surface_cosine * diffuse->g * light_color->g; 
    result->b += light_and_surface_cosine * diffuse->b * light_color->b; 
} 
 
void miaux_add_specular_hair_component( 
    miColor *result, miVector *hair_tangent, miVector *to_light, 
    miVector *to_camera, 
    miColor *specular, miColor *light_color) 
{ 
    miScalar light_angle = acos(mi_vector_dot(hair_tangent, to_light)); 
    miScalar view_angle = acos(mi_vector_dot(hair_tangent, to_camera)); 
    miScalar sum = light_angle + view_angle; 
    miScalar specular_factor = fabs(M_PI_2 - fmod(sum, M_PI)) / M_PI_2; 
 
    result->r += specular_factor * specular->r * light_color->r; 
    result->g += specular_factor * specular->g * light_color->g; 
    result->b += specular_factor * specular->b * light_color->b; 
} 
 
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_add_transparent_hair_component(miColor *result, miState *state) 
{ 
    miColor background_color; 
    mi_trace_transparent(&background_color, state); 
    if (result->a == 0) { 
	miaux_opacity_set_channels(state, 0.0); 
	miaux_copy_color(result, &background_color); 
    } else { 
	miaux_opacity_set_channels(state, result->a); 
	miaux_blend_colors(result, result, &background_color, result->a);  
    } 
} 
 
void miaux_opacity_set_channels(miState *state, miScalar value) 
{ 
    miColor opacity; 
    miaux_set_channels(&opacity, value); 
    mi_opacity_set(state, &opacity); 
} 
 
void miaux_copy_color(miColor *result, miColor *color) 
{ 
    result->r = color->r; 
    result->g = color->g; 
    result->b = color->b; 
    result->a = color->a; 
} 
 
void miaux_blend_colors(miColor *result,  
			miColor *color1, miColor *color2, miScalar factor) 
{ 
    result->r = miaux_blend(color1->r, color2->r, factor); 
    result->g = miaux_blend(color1->g, color2->g, factor); 
    result->b = miaux_blend(color1->b, color2->b, factor); 
} 
 
double miaux_blend(miScalar a, miScalar b, miScalar factor) 
{ 
    return a * factor + b * (1.0 - factor); 
} 

22 April 2008 23:40:43