Hi All! Marry Christmas and Happy New Year!!!!
Last three month I've been really busy and tightened with the publication of the second part. So now I wrote it. In a first gone the Illustrations and all shaders code and in a second a minor clarifications to certain parts of code.
Eye Shader Illustrations 1 from Alex Mirgorodsky on Vimeo.
The code:
class cEyeShader( uniform float EyeIrisXPosition = 0.5; uniform float EyeIrisYPosition = 0.5; uniform color EyeIrisInColor = (0.025, 0.05, 0.01); uniform color EyeIrisMidColor = (0.7, 0.3, 0.02); uniform color EyeIrisOutColor = (0.025, 0.05, 0.01); 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.1; float EyeIrisCausticLevel = 3; float EyeKd = 1; // Koeffs Diffuse float EyeWa = 0.2; // 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.0; string Category = "eye"; ) { 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; 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; } } 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)); //------ Assemble All Components --------------------------------------------------------- color outcolor = IrisColor_W_Diffuse; Oi = color(1); Ci=outcolor; } }I use synth of normal map for fake illumination of iris-pupil stria. Of course we could do it without any color implementations. But it easy for understanding of.
float tangent = angularDistribution(180); float binormal = angularDistribution(90); color tangentAngularMap = color(tangent, binormal, 0.5);
In a real eye( human eye) this is narrow groove. But in a cartoon animations we use exaggerations for most effects - and I make full Iris-size fake caustic highlight. In any case You may change the part of code for making "pupilIrisMask":
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;Diffuse Lighting of sclera I separate in two illumination loops. Lighting I make ONLY the special light with __category and a shadows I catching from all light in scene. And finnaly I make color remapping for the diffuse component of sclera by couples variables "ScleraHighlight-ScleraLowlight" and "ScleraCenterColorize-ScleraOutColorize"
In final third part - we will make reflection components for the Eye Shader.
next step 3
previous step 1
No comments:
Post a Comment