November 25, 2014

GLSL Eye ball

Just like the palm tree from earlier, I just made a step by step of iq's tutorial here of how he made an eye ball using shader code.

Here is his final result:


Let's do this!
First, we need a noise function.  Noise is used to add a randomized look, and if altered correctly, can give the image a natural, organic effect.  This is the noise function we will be using:


Let's make some noise!

    
Here we are using our noise function.

    
We made an fbm function (stands for fractal brownian motion) which is better explained elsewhere on the web.  But hey our noise looks better.
So we’ve replaced noise with fbm.  This is just to show what the fbm function looks like.

Now let's start making the eye.

    
Put a circle in the middle of our screen.  That will be the base of the eyeball.



    
Now we’re adding our fbm function.  Makes it look more interesting.

    
Add the pupil using smoothstep.

    
Add a yellow center

    
Let’s add a white pattern around the eye.


    
Alter the pattern by changing the parameters in our fbm function.


    
Back off on the white a bit using smoothstep.



    
Add some black flecks.


    
Actually, tweak the black flecks a bit.


Add a black border.


    
Edges are a bit aliased let’s fix that.


    
Apply some domain distortion to the atan to make the image a lil more interesting.  Here, we are changing the angle with some fbm.
(I’m moving the a declaration up a bit).


    
We can tweak the frequency to change the pattern!  Weird looking eye but the pattern could be used in cool ways for other things.

    
But let’s go for a more realistic eyeball.

Almost done!  Wouldn't a fake reflection make it look even better?

    
Whoa that's bright.


    
Better.


    
Some tweaking - make the reflection a bit bigger in smoothstep, move it a little in length, and when assigning to color give a slight yellowish tint and make it softer.



    
Add some animation to make it look creepy.  (Sorry, not animated here).


    
This just makes the animation non-uniform for different parts of the circle to make it even creepier.

//////////////////

And we're done!  Isn't that cool?
So here's the entire source code:
float hash( float n )
{
  return fract(sin(n)*43758.5453);
}

float noise( in vec2 x )
{
  vec2 p = floor(x);
    vec2 f = fract(x);
    f = f*f*(3.0-2.0*f);
    float n = p.x + p.y*57.0;
    float res = mix(mix( hash(n+  0.0), hash(n+  1.0),f.x),
    mix( hash(n+ 57.0), hash(n+ 58.0),f.x),f.y);
  return res;
}

float fbm(vec2 p) {
  float f = 0.0;
    f += 0.5000*noise(p); p *= 2.02;
    f += 0.2500*noise(p); p *= 2.03;
    f += 0.1250*noise(p); p *= 2.04;
    f += 0.0625*noise(p); p *= 2.01;
    f /= 0.9375;
    return f;
}

void main(void)
{
  vec2 uv = gl_FragCoord.xy / iResolution.xy;
    vec2 p = -1.0 + 2.0*uv;
    p.x *= iResolution.x/iResolution.y;
     
    float r = sqrt(dot(p,p));
    vec3 col = vec3(1.0);
     
    float ss = 0.5 + 0.5*sin(4.0*iGlobalTime);
  float anim = 1.0 + 0.1*ss*clamp(1.0 - r, 0.0, 1.0);
  r *= anim;
     
    if (r < 0.8) {
      col = vec3(0.0, 0.3, 0.4);  
         
     float a = atan(p.y, p.x);
        a += 0.05*fbm(20.0*p);
         
        // color variation
        float f = fbm(5.0*p);
   col = mix(col, vec3(0.2, 0.5, 0.4), f);
         
        // yellow center
     f = smoothstep(0.5, 0.2, r);
        col = mix(col, vec3(0.9, 0.6, 0.2), f);
         
        // white pattern
        f = fbm(vec2(5.0*r, 20.0*a));
     f = smoothstep(0.3, 1.0, f);
        col = mix(col, vec3(1.0), f);
         
        // black flecks
        f = fbm(vec2(10.0*r,16.0*a));
        f = smoothstep(0.4, 1.0, f);
        col *= (1.0 - f*0.7);
         
        // black border
        f = smoothstep(0.9, 0.55, r);
        col *= f;
         
        // reflection
        f = 1.0 - smoothstep(0.0, 0.3,
     length(p - vec2(0.25, 0.25)));
     col += vec3(1.0, 0.9, 0.8)*vec3(f)*0.7;
         
        // anti-aliasing
        f = smoothstep(0.75, 0.8, r);
        col = mix(col, vec3(1.0), f);
         
     // pupil
     f = smoothstep(0.2, 0.25, r);
        col *= f;
  }
     
    gl_FragColor = vec4(col, 1.0);
}

But I actually prefer green eyes so I made this one:

(link to shadertoy)