Mandelbrot Fractal

x축은 실수부, y축을 허수로 생각하는 공간(복소수평면)에서의 원점에서 일정한 offset 값만큼 이동하여 제곱한 값에 대한 실수부와 허수를 각각 x, y축으로 삼아 픽셀값으로 시각화한 결과가 Mandelbrot Fractal이며 구현 코드와 그에 대한 결과는 아래와 같다.

uniform vec3 uResolution;
uniform float uTime;
uniform vec4 uMouse;

void main() {
  vec2 uv = (gl_FragCoord.xy - .5 * uResolution.xy) / uResolution.y;
  uv += vec2(0.08, 0.15);
  vec2 c = uv * 2.5 + vec2(-.69955, -.37999); // Offset
  vec2 z = vec2(0.);
  float iter = 0.;
  float max_iter = 60.;

  float h = 2. + sin(uTime);
  for(float i=0.; i<max_iter; i++) {
    z = vec2(
      z.x * z.x - z.y * z.y, // 실수부
      2. * z.x * z.y // 허수부
    ) + c;
    if(length(z) > 2.) break;

    iter++;
  }

  float f = iter / max_iter;
  f = pow(f, .75);
  vec3 col = vec3(f);

  gl_FragColor = vec4(col, 1.0);
}

2개의 모양 함수를 smooth하게 섞는 방법(smooth min/max)

위에서 a와 b는 모양 함수(Shape Function)인데, a와 b의 값에 대한 min 또는 max 값을 취하면 a와 b를 하나로 섞을 수 있다. 그런데 a와 b의 교차점에서 매우 날카롭게 섞이게 되는데, 이를 부드럽게 섞은 것이 세번째 함수의 결과이다. 세번째 함수를 보면 k, h, m으로 구성되는데 이 중 k의 값에 따라 얼마나 부드럽게 섞을 것인지 결정한다. k 값이 음수일때 max 값으로 섞고 양수일때 min 값으로 섞는다.

float smin(float a, float b, float k) {
  float h = clamp(.5 + .5 * (b - a) / k, 0., 1.);
  return mix(b, a, h) - k * h * (1. - h);
}