Anime Style Eyes (Procedural Eye Shader)

This is a quite simple, but IMHO nice, procedural anime style eye shader. Creating an eye this way instead of using a simple texture has some advantages. So I wanted to explore these advantages. My shader has a specuar offset with different view angles, a very simple specular jitter animation, can track a target using a very simple script (for more details, look at the demo project), and I can play with the pupil size for dramatic effects. 

For more details, please take a look to the sample/demo project on my github and/or watch my youtube video for a detailed explanation of this shader (its in spanish).

As usual, hope you’ll like it 😋​

 

Shader code
shader_type spatial;
render_mode ambient_light_disabled, specular_disabled; // unshaded;

// this value should be controled with your script
uniform vec3 g_eye_direction = vec3(0.0, 0.0, 1.0); // in world coordinates

uniform vec2 g_eye_movement_limits = vec2(0.2, 0.2); // in UV space
uniform vec2 g_eye_scale = vec2(1.2, 1.0);
uniform vec3 g_iris_shadow = vec3(0.0, 0.25, 1.5); // xy = position offset, z = scale
uniform float g_outline_radius : hint_range(0.0, 1.0, 0.001) = 0.01;
uniform float g_radius = 0.2;
uniform float g_pupil_radius = 0.5; // relative size
uniform float g_specular_outline_radius : hint_range(0.0, 1.0, 0.001) = 0.01;
uniform vec2 g_specular_view_offset_mult = vec2(0.05, 0.025);
uniform vec3 g_specular_a = vec3(0.35, 0.35, 0.3); // xy = position, z = size (all relative to the eye
uniform vec3 g_specular_b = vec3(-0.35, -0.35, 0.15); // xy = position, z = size (all relative to the eye
uniform vec2 g_specular_jitter = vec2(0.05, 25.0); // size and speed
uniform vec3 g_outline_color : source_color = vec3(0.0, 0.0, 0.0);
uniform vec3 g_pupil_color : source_color = vec3(0.0, 0.0, 0.0);
uniform vec3 g_iris_color_a : source_color = vec3(0.3, 1.0, 0.3);
uniform vec3 g_iris_color_b : source_color = vec3(0.5, 0.5, 1.0);
uniform vec3 g_iris_shadow_color : source_color = vec3(0.7, 0.7, 0.7); // shadow
uniform vec3 g_specular_color : source_color = vec3(0.95, 0.975, 1.0);
uniform vec3 g_background_color : source_color = vec3(1.0, 1.0, 1.0);

// returns 0 if position is inside the circle, otherwise returns 1
float circle(vec2 position, float radius)
{
	return step(radius, length(position - vec2(0.5)));
}

// fills a circle
vec3 fill_circle(vec2 position, vec3 outside_color, vec3 inside_color, float radius)
{
	float c = circle(position, radius);
	return mix(inside_color, outside_color, c);
}

// strokes a circle
vec3 stroke_circle(vec2 position, vec3 outside_color, vec3 inside_color, float circle_radius, 
	float stroke_size)
{
	float outside = circle(position, circle_radius);
	float inside = circle(position, circle_radius - stroke_size);
	return mix(outside_color, inside_color, inside - outside);
}

// fills a circle but also cuts it with anothed circle mask
vec3 fill_masked_circle(
	vec2 mask_position, float mask_radius, vec3 mask_color, 
	vec2 position, float radius, vec3 outside_color, vec3 inside_color)
{
	vec3 in_out_color = fill_circle(position, outside_color, inside_color, radius);
	return fill_circle(mask_position, mask_color, in_out_color, mask_radius);
}

// draws a circle with stroke and fill colors
vec3 draw_circle(vec2 position, vec3 outside_color, vec3 stroke_color, vec3 fill_color, 
	float circle_radius, float stroke_size) 
{
	float outside_outline_val = circle(position, circle_radius);
	vec3 outside_outline_color = mix(stroke_color, outside_color, outside_outline_val);
	float inside_color_val = circle(position, circle_radius - stroke_size);
	return mix(fill_color, outside_outline_color, inside_color_val);	
}

void fragment() {
	// this is for the specular jitter
	float spc_jitter = 1.0 + (g_specular_jitter.x * sin(TIME * g_specular_jitter.y));		
	
	// compute the specular dynamic offset 
	vec2 specular_offset = NORMAL.xy * g_specular_view_offset_mult; 
	
	// compute local eye direction
	vec3 local_eye_direction = mat3(inverse(MODEL_MATRIX)) * normalize(g_eye_direction);
	
	// limit eye movement
	vec2 eye_position = (local_eye_direction.xy * g_eye_movement_limits);
	
	// convert from local space to uv space
	eye_position.y = -eye_position.y;
	eye_position += 0.5;
	
	// compute final uv with horizontal and vertical scaling 
	vec2 uv = ((UV - eye_position) * g_eye_scale) + vec2(0.5);

	// specular dots must be 100% circles and not ovals
	vec2 uv_specular = ((UV - eye_position) * g_eye_scale.xx) + vec2(0.5);
	
	// compute iris color (gradient)
	vec3 iris_color = mix(g_iris_color_a, g_iris_color_b, smoothstep(-g_radius, g_radius, uv.y - 0.5));
	
	// set initial color	
	vec3 current_color = g_background_color;
	
	// draw iris + shadow
	current_color = fill_masked_circle(uv, g_radius, current_color, uv - g_iris_shadow.xy, g_radius * g_iris_shadow.z, iris_color * g_iris_shadow_color, iris_color);
			
	// draw pupil
	current_color = fill_circle(uv, current_color, g_pupil_color, g_radius * g_pupil_radius); 

	// draw specular dots
	current_color = draw_circle(uv_specular + specular_offset + g_specular_a.xy * g_radius, current_color, g_outline_color, g_specular_color, g_specular_a.z * g_radius * spc_jitter, g_specular_outline_radius * g_radius);
	current_color = draw_circle(uv_specular + specular_offset + g_specular_b.xy * g_radius, current_color, g_outline_color, g_specular_color, g_specular_b.z * g_radius * spc_jitter, g_specular_outline_radius * g_radius);
	
	// draw outline
	current_color = stroke_circle(uv, current_color, g_outline_color, g_radius, g_outline_radius);
	
	// draw outside (to avoid specular dots outside the eye)
	current_color = fill_circle(uv, g_background_color, current_color, g_radius); 

	// set final color
	ALBEDO = current_color;
}
Live Preview
Tags
Anime, Eye, Procedural, toon
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from ProfesorShader

Related shaders

guest

0 Comments
Oldest
Newest Most Voted