跳到主要内容
← Signed Distance Field

Signed Distance Field

SDF Cat - Eyes

shader-learning 自学第 15 课:SDF Cat - Eyes

实时渲染 · 2D 片段 GLSL

第 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);
}