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(¶ms->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(¶ms->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(¶ms->root_opacity),
*mi_eval_scalar(¶ms->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(¶ms->specular);
*result = *mi_eval_color(¶ms->ambient);
result->a = alpha;
miaux_light_array(&light, &light_count, state,
¶ms->i_light, ¶ms->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