Going further than the tutorial:
- Made the eyes hazel
- Made small modifications to the mouth and highlights
GLSL / ShaderToy Code
#define S(a, b, t) smoothstep(a, b, t)
#define sat(x) clamp(x, 0.0, 1.0)
float remap01(float a, float b, float t) {
return sat((t - a) / (b - a));
}
float remap(float a, float b, float c, float d, float t) {
return sat((t - a) / (b - a)) * (d - c) + c;
}
vec2 within(vec2 uv, vec4 rect) {
return (uv - rect.xy) / (rect.zw - rect.xy);
}
vec4 createEye(vec2 uv) {
// Re-center uv
uv -= 0.5;
float dist = length(uv);
// Create iris
vec4 irisColor = vec4(0.396, 0.263, 0.129, 1.0);
vec4 irisColorInner = vec4(0.055, 0.169, 0.114, 0.5);
// White of the eye
vec4 color = vec4(1.0);
color = mix(color, irisColor, S(0.1, 0.7, dist) * 0.5);
// Edge shadow for white of eyes
color.rgb *= 1.0 - S(0.45, 0.5, dist) * 0.5 * sat(-uv.y - uv.x);
// Iris outline
color.rgb = mix(color.rgb, vec3(0.0), S(0.3, 0.28, dist));
irisColor.rgb *= 0.75 + S(0.35, 0.07, dist) * irisColorInner.rgb * 5.0;
irisColorInner.rgb *= 1.0 + S(0.2, 0.05, dist);
color.rgb = mix(color.rgb, irisColor.rgb, S(0.28, 0.27, dist));
//color.rgb = mix(color.rgb, irisColorInner.rgb, S(0.23, 0.20, dist));
// Pupil
color.rgb = mix(color.rgb, vec3(0.0), S(0.15, 0.14, dist));
// Highlights
float highlight = S(0.1, 0.05, length(uv - vec2(-0.15, 0.15)));
highlight += S(0.07, 0.01, length(uv - vec2(0.08, -0.08)));
color.rgb = mix(color.rgb, vec3(1.0), highlight);
color.a = S(0.5, 0.48, dist);
return color;
}
vec4 createMouth(vec2 uv) {
// Reset origin
uv -= 0.5;
vec4 color = vec4(0.5, 0.18, 0.05, 1.0);
uv.y *= 1.6;
uv.y -= uv.x * uv.x * 4.0;
float dist = length(uv);
color.a = S(0.3, 0.28, dist);
// Teeth
float teethDist = length(uv - vec2(0.0, 0.45));
vec3 teethColor = vec3(1.0) * S(0.6, 0.35, dist);
color.rgb = mix(color.rgb, teethColor, S(0.4, 0.37, teethDist));
// Tongue
float tongueDist = length(uv + vec2(0.0, 0.5));
color.rgb = mix(color.rgb, vec3(1.0, 0.5, 0.5), S(0.5, 0.2, tongueDist));
return color;
}
vec4 createHead(vec2 uv) {
// Orange color
vec4 color = vec4(0.9, 0.65, 0.1, 1.0);
// Create a circle
float dist = length(uv);
color.a = S(0.5, 0.49, dist);
// Create the edge shadow
float edgeShadow = remap01(0.35, 0.5, dist);
edgeShadow *= edgeShadow;
color.rgb *= 1.0 - edgeShadow * 0.5;
// Create outline
color.rgb = mix(color.rgb, vec3(0.6, 0.3, 0.1), S(0.4799, 0.48, dist));
// Create highlight
float highlight = S(0.41, 0.39, dist);
highlight *= remap(0.41, -0.1, 0.75, 0.0, uv.y);
color.rgb = mix(color.rgb, vec3(1.0), highlight);
// Create cheeks
dist = length(uv - vec2(0.25, -0.2));
float cheek = S(0.2, 0.01, dist) * 0.3;
cheek *= S(0.17, 0.16, dist);
color.rgb = mix(color.rgb, vec3(1.0, 0.1, 0.1), cheek);
return color;
}
vec4 createSmiley(vec2 uv) {
vec4 color = vec4(0.0);
// Mirror face
uv.x = abs(uv.x);
vec4 head = createHead(uv);
vec4 eye = createEye(within(uv, vec4(0.03, -0.1, 0.37, 0.25)));
vec4 mouth = createMouth(within(uv, vec4(-0.3, -0.41, 0.3, -0.11)));
color = mix(color, head, head.a);
color = mix(color, eye, eye.a);
color = mix(color, mouth, mouth.a);
return color;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord.xy / iResolution.xy;
// Move origin to the center
uv -= 0.5;
// Account for aspect ratio
uv.x *= iResolution.x / iResolution.y;
vec3 color = vec3(0.0);
// Output to screen
fragColor = createSmiley(uv);
}
Tutorial I followed:
Resources:
ShaderToy