This is the last component needed for our shader eyes - specular glare and reflections.
ReflectivityComponents_SpecAndSpecRefl from Alex Mirgorodsky on Vimeo.
// cEyeShader.sl written by Alex Mirgorodsky // any questions about this shader code send on my e-mail: amir543@gmail.com // This code free to copy and distribute. class cEyeShader( uniform float EyeIrisXPosition = 0.5; uniform float EyeIrisYPosition = 0.5; uniform color EyeIrisInColor = (0.322, 0.18, 0.0); uniform color EyeIrisMidColor = (0.541, 0.278, 0.063); uniform color EyeIrisOutColor = (0.322, 0.18, 0.0); uniform float EyePupilRadius = 0.03; uniform float EyeIrisRadius = 0.06; uniform float EyeIrisSeed = 1; uniform float EyeIrisCircularNoiseLevel = 0.2; uniform float EyeIrisRadialNoiseLevel = 0.75; uniform float EyeIrisRadialShift = 0.3; float EyeIrisMinLevel = 0.05; float EyeIrisCausticLevel = 3; float EyeKd = 0.7; // Koeffs Diffuse float EyeWa = 0.1; // Wideness Light Angle color ScleraHighlight = color(0.835, 0.9, 0.965); color ScleraLowlight = color(0.234, 0.234, 0.276); color ScleraCenterColorize = color(1); color ScleraOutColorize = color(1); float OffsetCircularColor = 3; float EyeShadowLevel = 0.1; string Category = "eye"; // Specular float EyeKs = 1; float SpecularRoughness = 0.003; float SpecularSharpness = 0.9; // Reflection float Refectivity = 1.0; float MaxDistance = 256; uniform float ReflSamples = 3; ) { uniform float pi2 = 6.283185307; shader lights[] ={}; shader categoryLights[] = {}; shader notCategoryLights[] = {}; constant float countLights = 0; constant float countCategoryLights = 0; constant float countNotCategoryLights = 0; float linstep(float min, max, x) { float f; if (x < min) f = 0; if (x >= max) f = 1; f = (x-min)/(max-min); return f; } float IrisNoise() { float angle; uniform float noiseScale1 = 100; uniform float noiseScale2 = 500; float d = distance(point(EyeIrisXPosition, EyeIrisXPosition, 0), point(s, t, 0)); if (d != 0) angle = asin((EyeIrisYPosition-t)/d); else angle = 0; if (EyeIrisXPosition-s < 0) angle = PI - angle; float n1 = noise(s*noiseScale1, t*noiseScale1) * clamp(noise(s*noiseScale2, t *noiseScale2),.5, 1) * 2; float n2 = noise(angle*5+EyeIrisSeed); n1 = (n1 * EyeIrisCircularNoiseLevel) + (1-EyeIrisCircularNoiseLevel); n2 = (n2 * EyeIrisRadialNoiseLevel) + (1-EyeIrisRadialNoiseLevel); return n1*n2; } normal NormalSurf() { normal Ns ; normal Nn = normalize(N); uniform float depth; rayinfo("depth", depth); if(depth > 0) Ns = faceforward(Nn, normalize(I), Nn); else { uniform float sides = 2; attribute("Sides", sides); if(sides == 2) Ns = faceforward(Nn, normalize(I), Nn); else Ns = Nn; } return Ns; } float angularDistribution(float rotationAngle) { float angleRad = radians(rotationAngle); float Sn = s-EyeIrisXPosition; float Tn = t - EyeIrisYPosition; float S_Rot = (Sn* cos(angleRad) - Tn*sin(angleRad)) + EyeIrisXPosition; float T_Rot = (Tn* cos(angleRad) + Sn*sin(angleRad)) + EyeIrisYPosition; float ss = (atan(T_Rot-EyeIrisYPosition, S_Rot-EyeIrisXPosition) + PI) / pi2; float outputDistribution = float spline ("bspline", ss, 1, 1, 0.5, 0, 0.5, 1, 1); return outputDistribution; } public void construct() { lights = getlights(); countLights = arraylength(lights); uniform string __category; uniform float i; for (i = 0; i < countLights; i += 1) { getvar(lights[i], "__category", __category); if(__category == Category) { push(categoryLights, lights[i]); } else { push(notCategoryLights, lights[i]); } } countCategoryLights = arraylength(categoryLights); countNotCategoryLights = arraylength(notCategoryLights); } public void surface(output color Ci, Oi) { // Dummy Difuse Color color Diffuse = color(1); // Pupil color (You can make your self solution for Pupil Lighting. But I use siple black color. color PupilColor = color(0); float RadialDistribution = sqrt(pow((s-EyeIrisXPosition), 2) + pow((t-EyeIrisYPosition),2)); float reDistribution = RadialDistribution / (EyeIrisRadius-EyePupilRadius); float kKorrection = EyePupilRadius / (EyeIrisRadius-EyePupilRadius); float kSpline = float spline( "linear", reDistribution, kKorrection, kKorrection, (EyeIrisRadialShift + kKorrection), (1 + kKorrection), (1 + kKorrection)); color IrisPainting = color spline( "linear", kSpline, EyeIrisInColor, EyeIrisInColor, EyeIrisMidColor, EyeIrisOutColor, EyeIrisOutColor); IrisPainting = IrisPainting * IrisNoise(); // Add Noise to Iris color IrisColor_W_Pupil = mix(PupilColor, IrisPainting , clamp(linstep( EyePupilRadius, (EyePupilRadius +(EyePupilRadius/100)), RadialDistribution),0,1)); //------ Calculate Fake Tangent Map ------------------------------------------------------- float tangent = angularDistribution(180); float binormal = angularDistribution(90); color tangentAngularMap = color(tangent, binormal, 0.5); normal Ns = NormalSurf(); normal Tangent = normal(tangentAngularMap); normal ReTangent = 2*Tangent - normal(1,1,1); //ReTangent = normal(ReTangent[0], ReTangent[1], ReTangent[2]); ReTangent = transform("object", "current", ReTangent); normal Unit = normal(0,0,1); normal ReNormal = normalize(Ns +(Unit - ReTangent)); //------ Lighting ---------------------------------------------------------------------------------- color fakeCaustic=0; float nondiff = 1; float InputAngle = -EyeWa*2; color diffColor = 0; //_lightingstart(); uniform float i; for (i = 0; i < countCategoryLights; i += 1) { vector L; color Cl =0; float LightAngle; categoryLights[i]->light(L, Cl); //------Fake Caustic Computing ------------------------------------------------------ float ratio = ReNormal.normalize(-L); fakeCaustic += pow((1+ratio)/2, 2); //------ Diffuse Computing With WDA------------------------------------------------- LightAngle = normalize(-L).Ns; if(Ns.I > 0) LightAngle = -LightAngle; LightAngle = clamp(LightAngle,InputAngle,1); LightAngle = (LightAngle - InputAngle) / (1 - InputAngle); getvar(categoryLights[i], "__nondiffuse", nondiff); if (nondiff <1) { diffColor += (1-nondiff) * Cl * LightAngle; } } //------- Shadows computing ---------------------------------------------------------------- color inshadow=0; color accumShadow = 0; float accumRatio = 0; for (i = 0; i < countLights; i += 1) { vector L; color Cl =0; lights[i]->light(L, Cl); if( 0 != getvar(lights[i], "_shadow", inshadow)) { accumShadow += inshadow; } } //accumRatio = accumRatio/countLights; color shadowHSL = ctransform("hsl", accumShadow); float shadowCalc = 1 - shadowHSL[2]*EyeShadowLevel; //------- Fake Caustic -------------------------------------------------------------------------- float pupilMask = clamp(smoothstep( EyePupilRadius, (EyePupilRadius +(EyePupilRadius/2)),RadialDistribution),0,1); float irisMask = clamp(smoothstep((EyeIrisRadius - (EyePupilRadius/2)), EyeIrisRadius, RadialDistribution),0,1); float pupilIrisMask = (1-irisMask)* pupilMask; float causticComp = clamp((EyeIrisMinLevel + EyeIrisCausticLevel*pow(fakeCaustic[0], 2)*pupilIrisMask), 0,1); //------- Assemble Diffuse Components --------------------------------------------------- color diffuseHSL = ctransform("hsv", (diffColor*shadowCalc)); color scleraColorRemap = mix(ScleraLowlight, ScleraHighlight, pow(diffuseHSL[2], 3)); float Sn = s-EyeIrisXPosition; float Tn = t - EyeIrisYPosition; Sn = 1 - sqrt(2 * (Sn * Sn + Tn * Tn)); color CircularColor = mix(ScleraOutColorize, ScleraCenterColorize, pow(Sn,(1+OffsetCircularColor))); color IrisColor_W_Diffuse = mix(IrisColor_W_Pupil*causticComp, scleraColorRemap*CircularColor, filterstep(EyeIrisRadius, RadialDistribution)); //------ Reflective Components ------------------------------------------------------------- float fkr, fkt; vector Refl, Refr; vector In = normalize(I); fresnel(In, Ns, 1.75187, fkr,fkt, Refl, Refr); //-------------------- Specular ------------------------------------------------------------------ vector V = -normalize(I); color spec_color = 0; float glossyRegion = SpecularSharpness/2; float nonspec = 0; color specular = 0; //vector Refl = reflect(normalize(I), normalize(N)); color specOut = 0; for (i = 0; i < countCategoryLights; i += 1) { vector L; color Cl; categoryLights[i]->light(L, Cl); float nonspec = 0; getvar(categoryLights[i], "__nonspecular", nonspec); // getting specular weight koef from light vector H = normalize(normalize(-L)+V); // Halfway vector specular = Cl*(1-nonspec); spec_color += specular * (smoothstep (glossyRegion ,1-glossyRegion , pow(max(0,Ns.H), 1/SpecularRoughness))); } //---------------------- Environment Reflection -------------------------------------------- vector ReflDir = reflect(normalize(I), Ns); color specularIndirect = 0; /* The pseudo Fresnel term - like Schlick Aproximation */ float FrenelTerm = 1 - pow(normalize(-I).Ns, 0.6); color reflAccumulation = 0; color reflColor = 0; /* Reflection map. I use renderman user option string usually for sent to a the scene shaders. But for example I use simle string */ string envMap = "street.env"; gather("illuminance", P, ReflDir, 0, ReflSamples, "distribution", "cosine", "maxdist", MaxDistance, "volume:Ci", reflColor) { reflAccumulation += reflColor; } else { ReflDir = transform ("ReflEnvMapCoordsys", ReflDir); reflAccumulation += environment(envMap, ReflDir, "width", 1 ); } specularIndirect = (reflAccumulation / ReflSamples) * FrenelTerm * Refectivity; //------ Assemble All Components --------------------------------------------------------- color outcolor = IrisColor_W_Diffuse+spec_color+specularIndirect; Oi = color(1); Ci=outcolor; } }The next final step will be a small tuning to a custom specular shapes - a rectangle and ellipse.
Coming soon
Thanks, Alex, very nice and useful.
ReplyDeleteYou're welcome!
ReplyDeleteHi Alex.
ReplyDeleteFirst, thanx for the shader, and for the explanations.
I am new to Renderman programing, and so my question will probably be a laughing matter for most guys here. But still, I need to ask...
:)
My problem starts with the lighting - after putting in the parts concerning highlights and the rest (part two of your shader and onward), I can't get any light on it, no matter what I do.
I tried, of course, everything I know (though it's not much...) - re-checking ENV variables, trying various lights and attributes both of Renderman and Maya.
I'd like to know if anybody else had the same problem, or if anyone has an idea about the reasons.
Thanks again,
Moshe