Shader Toy - Fractal

Date:     Updated:

카테고리:

태그:

유튜브 kishimisu의 An introduction to Shader Art Coding 영상을 정리한 내용입니다.
중간에 등장하는 자료들은 영상을 캡처한 것입니다.
이번 포스팅의 예제는 Shadertoy 에서 GLSL로 진행했습니다.


🐥 UV 좌표계 수정

origin resolution downsampled resolution
1 2
void main(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;  // 0 ~ 1
    
    uv = uv - 0.5; // align center
    uv = uv * 2.0; // -1 ~ 1

    fragColor = vec4(uv, 0.0, 1.0);
}
  • 스크린의 중앙을 기준으로 작업을 하기 때문에 uv 좌표계를 center 중심으로 바꿔주기


🐥 Fix Aspect Ratio

Before Fix After Fix
4 3
void main(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = fragCoord / iResolution.xy;  // 0 ~ 1
    
    uv = uv - 0.5; // align center
    uv = uv * 2.0; // -1 ~ 1

    fragColor = vec4(uv, 0.0, 1.0);
}
  • 일반적으로 모니터의 가로x세로 해상도가 다르기 때문에 정사각형 모양의 스크린을 원한다면 aspect ratio를 보정해야 한다.


🐥 2D Signed Distance Function

5

void main(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
    
    float d = length(uv);
    d -= 0.5;
    d = abs(d);

    fragColor = vec4(d, d, d, 1.0);
}
  • 물체의 표면을 표현하고 싶을 때 사용하는 SDF
  • Signed Distance Function : 물체의 형태를 유지하는 level set
    • negative : 물체 내부
    • zero : 물체 표면
    • positive : 물체 외부
  • absolute value, abs()를 이용하여 내부, 외부 모두 흰색으로 만들어주기
  • Q ) 경계면 좀 더 깔끔하게 만들 수는 없나..??


Step Function

Graph Result
5 6
  • step function을 이용하면 칼 같은 경계 표현 가능


Smoothstep Function

Graph Result
7 8
  • smoothstep으로는 원하는 두께로 부드럽게 표현 가능


🐥 Sine 함수로 주기 만들기

9

void main(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
    
    float d = length(uv);

    d = sin(d * 8.0 + iTime) / (8.0);
    d = abs(d);

    d = smoothstep(0.0, 0.1, d);

    fragColor = vec4(d, d, d, 1.0);
}
  • sine function을 이용하여 주기를 주고
  • iTime을 더해주며 움직임 표현


🐥 1/x 함수로 색 반전시키기

Graph Result
10 11
void main(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
    
    float d = length(uv);

    d = sin(d * 8.0 + iTime) / (8.0);
    d = abs(d);

    d = 0.01 / d;

    fragColor = vec4(d, d, d, 1.0);
}
  • 색을 반전시키기 위해서는 0 -> 1, 1 -> 0 으로 부드럽게 변경해야 함
  • 1/x 함수를 이용하면 원하는 강도로 부드럽게 반전시킬 수 있다.
  • color 곱해주면 알록달록 표현 가능


Example1 Example2
12 13


🐥 Palette 만들기

vec3 palette(float t)
{
    vec3 a = vec3(0.5, 0.5, 0.5);
    vec3 a = vec3(0.5, 0.5, 0.5);
    vec3 a = vec3(1.0, 1.0, 1.0);
    vec3 a = vec3(0.263, 0.416, 0.557);

    vec3 a + b*cos(6.28318 * (c*t + d));
}


void main(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
    
    float d = length(uv);

    vec3 col = palette(d + iTime);

    d = sin(d * 8.0 + iTime) / (8.0);
    d = abs(d);

    d = 0.02 / d;

    col *= d;

    fragColor = vec4(col, 1.0);
}

16

Inigo Quilez website

  • 위 사이트에 들어가면 원하는 팔레트의 변수 값들을 찾을 수 있음
  • 연속적으로 색이 변하는 팔레트이기 때문에 시간에 따른 주기함수에 쓰기 좋다.
  • palette 변수로 time을 더해주면 같은 원 내에서도 알록달록 변함


Example1 Example2
15 14


🐥 Fraction 함수로 스크린 분할

Graph Result
17 18
void main(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y; // -1 ~ 1
    
    uv = fract(uv * 2.0) - 0.5; // -2 ~ 2 : 가로세로 4등분 & center 보정
    
    float d = length(uv);

    vec3 col = palette(d + iTime);

    d = sin(d * 8.0 + iTime) / (8.0);
    d = abs(d);

    d = 0.02 / d;

    col *= d;

    fragColor = vec4(col, 1.0);
}
  • fraction : 정수 부분을 뺀 소수 부분
  • uv의 범위를 늘려주고 fraction을 이용하면 스크린을 반복할 수 있음


Global Effect 추가하기

ezgif com-video-to-gif (6)

void main(out vec4 fragColor, in vec2 fragCoord)
{
    vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y; // -1 ~ 1
    vec2 uv0 = uv; // glbal coordinate

    uv = fract(uv * 2.0) - 0.5; // -2 ~ 2 : 가로세로 4등분 & center 보정
    
    float d = length(uv);

    vec3 col = palette(length(uv0) + iTime); // global effect

    d = sin(d * 8.0 + iTime) / (8.0);
    d = abs(d);

    d = 0.02 / d;

    col *= d;

    fragColor = vec4(col, 1.0);
}
  • fraction 적용 전 global coordinate(?)을 저장해두고, 이를 이용하여 global effect를 만들어 줄 수 있다.


🐥 Iteration으로 Fractal 구조 만들기

ezgif com-video-to-gif (7)

void main( out vec4 fragColor, in vec2 fragCoord )
{
     vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
     vec2 uv0 = uv;
     vec3 finalColor = vec3(0.0);
     
     for(float i=0.0; i<2.0; i++) 
     {
         uv = fract(uv * 2.0) - 0.5;

         float d = length(uv);

         vec3 col = palette(length(uv0) + iTime);

         d = sin(d*8. + iTime) / 8. ;
         d = abs(d);

         d = 0.02  / d;

         finalColor += col * d;
     }
     
     fragColor = vec4(finalColor, 1.0);
}
  • fraction으로 쪼갠 영역 안에서 또 fraction으로 쪼개버리기
  • i를 늘려주면서 fractal 구조 만들 수 있음


🐥 Final Results

void main( out vec4 fragColor, in vec2 fragCoord )
{
     vec2 uv = (fragCoord * 2.0 - iResolution.xy) / iResolution.y;
     vec2 uv0 = uv;
     vec3 finalColor = vec3(0.0);
     
     
     for(float i=0.0; i<4.0; i++) 
     {
         uv = fract(uv * 1.5) - 0.5;

         float d = length(uv) * exp(-length(uv0));

         vec3 col = palette(length(uv0) + i*0.4 + iTime*0.4);

         d = sin(d*8. + iTime) / 8. ;
         d = abs(d);

         d = pow(0.01 / d, 1.2);

         finalColor += col * d;
     }
     
     fragColor = vec4(finalColor, 1.0); 
}
  • 규칙성을 흩트려 뜰이기 위해 몇 가지 작업 수행
  • for문 안에서 2.0이 아닌 1.5배로 애매하게 쪼개기
  • d = x * exp(-x), 부드러운 형태로 변형
  • 0~1 사이에 pow 함수를 적용해 어두운 부분은 더 어둡게 표현


ezgif com-crop (4)



맨 위로 이동하기

Mini_Project 카테고리 내 다른 글 보러가기

댓글 남기기