第 15 课:SDF Cat - Eyes
实现
uniform vec2 iResolution;
uniform float iTime;
const vec3 shapeColor = vec3(1.0, 0.3, 0.3);
const vec3 backgroundColor = vec3(0.12);
float sdfCircle(vec2 center, float r, vec2 pos) {
return distance(center, pos) - r;
}
float sdfBox(vec2 center, vec2 size, vec2 pos) {
vec2 d = abs(pos - center) - size;
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
}
float softMax(float a, float b, float k) {
return log(exp(k * a) + exp(k * b)) / k;
}
float softMin(float a, float b, float k) {
return -softMax(-a, -b, k);
}
mat2 rotation(float theta){
return transpose(mat2(
vec2(cos(theta),-sin(theta)),
vec2(sin(theta),cos(theta))
));
}
vec2 symmetryX(vec2 uv){
return vec2(abs(uv.x), uv.y);
}
float makeEar(vec2 center, vec2 uv){
float earH = 60.0;
float timeOffset = -3.14;
vec2 newUv = rotation(0.628+sin(iTime + timeOffset)*0.1)*symmetryX(uv);
float earA = sdfCircle(center + vec2(-35.0,earH), 60.0, symmetryX(newUv));
float earA_inn = sdfCircle(center + vec2(-35.0,earH-5.0), 60.0, symmetryX(newUv));
return max(earA, -earA_inn);
}
float makeWhiskers(vec2 center, vec2 uv){
float whiskerLength = 35.0;
float timeOffset = -3.14;
vec2 uv_rotation_up = rotation(0.314+sin(iTime + timeOffset)*0.1)*symmetryX(uv);
vec2 uv_rotation_low = rotation(0.628+sin(iTime + timeOffset)*0.1)*symmetryX(uv);
float whiskerUpper = sdfBox(center + vec2(60.0,-10.0), vec2(whiskerLength, 1.0), uv_rotation_up);
float whiskerLower = sdfBox(center + vec2(60.0,-10.0), vec2(whiskerLength, 1.0), uv_rotation_low);
return min(whiskerUpper, whiskerLower);
}
float makeCheek(vec2 center, vec2 uv){
float cheekHeight = -20.0;
float timeOffset = -3.14;
vec2 offset = vec2(0.0, sin(iTime + timeOffset) * 2.0);
float cheek = sdfCircle(center + vec2(12.0,cheekHeight) + offset, 15.0, symmetryX(uv));
float cheek2 = sdfCircle(center + vec2(12.0,cheekHeight)+vec2(-2.0,2.0) + offset, 15.0, symmetryX(uv));
return max(cheek,-cheek2);
}
float makeNose(vec2 center, vec2 uv){
float timeOffset = -3.14;
vec2 offset = vec2(0.0, sin(iTime + timeOffset) * 2.0);
float nose1 = sdfCircle(vec2(10.0,-14.0) + offset, 11.0, uv);
float nose2 = sdfCircle(vec2(-10.0,-14.0) + offset, 11.0, uv);
float nose3 = sdfCircle(vec2(0.0,-7.0) + offset, 10.0, uv);
return max(nose3,max(-nose2,-nose1));
}
float makeEyes(vec2 center, vec2 uv){
float timeOffset = -3.14;
vec2 offset = vec2(0.0, sin(iTime + timeOffset) * 2.0);
float eye1 = sdfCircle(vec2(20.0, 20.0) + offset, 15.0, symmetryX(uv));
float eye2 = sdfCircle(vec2(25.0, 25.0) + offset, 15.0, symmetryX(uv));
return -max(eye1,eye2);
}
float makePupils(vec2 center, vec2 uv){
float timeOffset = -3.14;
vec2 offset = vec2(0.0, sin(iTime + timeOffset) * 2.0);
float eye1 = sdfCircle(vec2(10.0, 20.0) + offset, 15.0, symmetryX(uv));
float eye2 = sdfCircle(vec2(32.0, 22.0) + offset, 15.0, symmetryX(uv));
return max(eye1,eye2);
}
void main() {
vec2 uv = gl_FragCoord.xy;
// make 0 the center
uv.x -= iResolution.x * 0.5;
uv.y -= iResolution.y * 0.5;
vec2 center = vec2(0.5);
float head = sdfCircle(center, 60.0 + sin(iTime), uv);
float ear = makeEar(center, uv);
float whiskers = makeWhiskers(center, uv);
float cheeks = makeCheek(center, uv);
float nose = makeNose(center, uv);
float eyes = makeEyes(center, uv);
float pupiles = makePupils(center, uv);
float u = -softMin(ear, head, 0.25) *min(eyes,pupiles)* min(whiskers, cheeks) * nose;
float t = clamp(u, 0.0, 1.0);
gl_FragColor = vec4(mix(shapeColor, backgroundColor, t), 1.0);
}