Here’s a fun OSL texture that give you hair color defined by Melanin and Dye color parameters, based on the paper “An Energy-Conserving Hair Reflectance Model”
Usage: The resulting texture hair color goes in “transmission color” and “diffuse color” of a VrayHairMtl3, with the “diffuse value” ideally less than 0.5. The secondary specular is the hair color multiplied with itself (which is what the “lock secondary” checkbox in the VrayHairMtl does).
Some additional notes: I used a color for the melanin amount since there are no sliders for floats in Vray’s OSL in Maya, and colors have sliders. I just grabbed the red channel. Kinda sloppy, so perhaps someone has some ideas about a better way to do that. I’m thinking maybe a luminance().
Also I wanted the ability to put a texture map into the dye color. When you do that the color defaults to black, but the dye color should be white by default (if there is no dye). I used the gettextureinfo function to get it to actually default to white in the texture, but it still appears black in the attribute editor. So again, if folks have any ideas about how to address this, I’m all ears!
/*
*
* Hair color defined by Melanin and Dye color parameters
* based on the paper "An Energy-Conserving Hair Reflectance Model"
* http://www.eugenedeon.com/wp-content/uploads/2014/04/egsrhair.pdf
* written for OSL by Derek Flood
* from http://docs.sharktacos.com/misc.php?action=help&hid=66
*
*/
color getTextureDif(string texture_name, color no_texture_default_color)
{
int channels = -1;
if (gettextureinfo(texture_name, "channels", channels))
{
return texture(texture_name, u, v);
}
return no_texture_default_color;
}
shader hairColorTex
[[ string description = "Hair color defined by Melanin and Dye color parameters " ]]
(
string Dye_color = "color.png"
[[ string description = "White for non-dyed hair. If using a map,
put it here and set Melanin Amount to zero" ]],
color Melanin_amount = 0.3
[[ string description = "Melanin concentration in hair fiber (from 0 to 1).
0.0 is white hair, 0.2 is blond, 0.3 is auburn, ... until you get to 1.0 for black hair.
Since there are no sliders, we use a color and grab the red channel" ]],
float Texture_Gamma = 1,
output color result = 0
)
{
/* Read texture map or default to white color */
color DyeColor = getTextureDif(Dye_color, color(1,1,1));
/* Compute a perceptualy linear absorption weight from Melanin_amount */
float Weight = max( pow(Melanin_amount[2], 2.0) * 33.0, 0.02);
/* The fiber color is actually an absorption term. As light travels through fibers,
melanin particles filter out some wavelength. We compute it using Beer's Law. */
color hairColor = exp(Weight * -color(0.187, 0.4, 1.05));
/* Now we model the dying process as a thin transparent film over the fiber that will filter transmitted light.
This is simply a multiplication. */
hairColor *= DyeColor;
/* Finally we derive the values for the transmission and secondary specular,
which is the value of the hairColor squared. */
result=pow(hairColor, Texture_Gamma); //optionally gamma correct color
}