본문 바로가기
Graphics/GLSL

04. Shaping functions

by Lein_ 2021. 12. 30.

Algorithmic drawing

 

Shaping functions

이번 장에서는 모양을 그릴 때 유용한 함수들을 소개한다. 먼저 예제 코드부터 살펴보자.

 

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

// Plot a line on Y using a value between 0.0-1.0
float plot(vec2 st) {    
    return smoothstep(0.02, 0.0, abs(st.y - st.x));
}

void main() {
    vec2 st = gl_FragCoord.xy/u_resolution;

    float y = st.x;

    vec3 color = vec3(y);

    // Plot a line
    float pct = plot(st);
    color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0);

	gl_FragColor = vec4(color,1.0);
}

 

smoothstep 함수의 원형은 다음과 같다.

 

float smoothstep(float edge0, float edge1, float x)

 

edge0 < x < edge1 일 때 x의 값을 0~1 사이의 값으로 보간한다. smoothstep()의 내부는 다음과 같다.

 

    genType t;  /* Or genDType t; */
    t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
    return t * t * (3.0 - 2.0 * t);

 

삼차식이므로 보다 부드럽게 보간된다.

 

 

자세한 내용은 https://thebookofshaders.com/glossary/?search=smoothstep 를 참조하도록 하자.

 

위 예제는 완벽하게 이해하고 넘어가는 것이 좋다. 코드를 관찰하고 변형하며 터득하길 바란다.

이러한 x와 y(또는 밝기) 사이의 일대일 관계를 선형 보간(linear interpolation)이라고 한다. 선을 형성하기 위해 여러 수학적 함수를 사용할 수 있다. 예를 들어, x를 5의 거듭제곱으로 올려 곡선으로 만들 수 있다.

 

// Author: Inigo Quiles
// Title: Expo

#ifdef GL_ES
precision mediump float;
#endif

#define PI 3.14159265359

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

float plot(vec2 st, float pct){
  return  smoothstep( pct-0.02, pct, st.y) -
          smoothstep( pct, pct+0.02, st.y);
}

void main() {
    vec2 st = gl_FragCoord.xy/u_resolution;

    float y = pow(st.x,5.0);

    vec3 color = vec3(y);

    float pct = plot(st,y);
    color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0);

    gl_FragColor = vec4(color,1.0);
}

첫 번째 예제보다 부드러운 곡선임을 관찰할 수 있다. 22번째 줄의 pow 안의 두 번째 인자값을 다양하게 바꿔보자. (20.0, 2.0, 1.0, 0.0, 0.2, 0.02 ... 등) 값과 지수 사이의 관계를 이해하는 데 도움이 될 것이다. 이런 수학 함수를 사용하면 값의 흐름을 조절할 수 있다.

 

pow()는 GLSL의 고유 함수이며 다른 함수들도 많이 있다. 대부분은 하드웨어 수준에서 가속되므로 올바른 방법으로 신중하게 사용하면 코드를 더 빠르게 만들 수 있다.

 

pow를 다른 함수로 대체하는 것도 가능하다. exp(), log() 및 sqrt()와 같은 함수도 사용해보자. PI를 이용하면 흥미로운 결과를 볼 수 있다. PI는 주로 3.141592659와 같은 값을 매크로로 정의해 사용한다.


Step과 Smoothstep

 

GLSL은 하드웨어 가속화된 고유한 보간 함수를 갖고 있다.

 

step() 보간은 두 개의 인자를 받는다. 첫 번째는 한계 또는 임계값이고 두 번째는 통과시킬 값이다. 제한보다 작은 값은 0.0을 반환하고 제한보다 큰 값은 1.0을 반환한다.

float step(float edge, float x)

 

다음은 step을 사용한 예제이다.

 

#ifdef GL_ES
precision mediump float;
#endif

#define PI 3.14159265359

uniform vec2 u_resolution;
uniform float u_time;

float plot(vec2 st, float pct){
  return  smoothstep( pct-0.02, pct, st.y) -
          smoothstep( pct, pct+0.02, st.y);
}

void main() {
    vec2 st = gl_FragCoord.xy/u_resolution;

    // Step will return 0.0 unless the value is over 0.5,
    // in that case it will return 1.0
    float y = step(0.5,st.x);

    vec3 color = vec3(y);

    float pct = plot(st,y);
    color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0);

    gl_FragColor = vec4(color,1.0);
}

step의 첫 번째 인자 값을 바꿔보며 관찰해보자.

 

다른 대표적인 보간 함수로는 위에서 살펴본 smoothstep()이 있다. 두 숫자와 값의 범위가 주어지면 정의된 범위 사이에 값을 보간한다. 앞에서 두 개의 파라미터는 변환의 시작과 끝에 대한 파라미터, 세 번째 파라미터는 보간할 값에 대한 파라미터이다.

 

#ifdef GL_ES
precision mediump float;
#endif

#define PI 3.14159265359

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

float plot(vec2 st, float pct){
  return  smoothstep( pct-0.02, pct, st.y) -
          smoothstep( pct, pct+0.02, st.y);
}

void main() {
    vec2 st = gl_FragCoord.xy/u_resolution;

    // Smooth interpolation between 0.1 and 0.9
    float y = smoothstep(0.1,0.9,st.x);

    vec3 color = vec3(y);

    float pct = plot(st,y);
    color = (1.0-pct)*color+pct*vec3(0.0,1.0,0.0);

    gl_FragColor = vec4(color,1.0);
}

12번째 줄에서는 plot() 함수에 녹색 선을 그리기 위해 smoothstep을 사용하고 있다.

20번 째 줄을 아래의 코드로 대체해보자.

 

float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x);

Sine과 Cosine

 

값을 애니메이션화하거나 모양을 만들거나 혼합할 때는 sine, cosine만한 것이 없다.

어떻게 동작하고 어떤 방식으로 결합되는지 아는 것이 중요하다. 간단히 말하면, 라디안 단위로 주어진 각도는 반지름이 1인 원의 가장자리에 있는 점의 x(코사인)과 y(사인)의 정확한 위치를 반환한다. 정규화된 값(-1과 1사이의 값)을 매우 부드럽게 반환한다는 사실이 중요한 점이다.

 

위 사진은 이러한 관계를 시각적으로 보여준다.

 

 

y = sin(x);

사인파의 부드러운 곡선을 보면 GLSL 코딩에 얼마나 유용할지 알 수 있을 것이다.

 

다음과 같은 시도를 해보고 어떤 결과가 나타나는지 관찰해보자.

 

1. sin을 계산하기 전에 x에 시간(u_time)을 더해보자. x를 따라 그 움직임을 내면화해보자.

 

2. sin을 계산하기 전에 x에 PI를 곱해보자. 두 위상이 축소되어 각 사이클이 2개의 정수마다 반복되도록 한다.

 

3. sin을 계산하기 전에 시간(u_time)에 x를 곱해보자. 위상 간 빈도가 점점 더 압축되는 것을 관찰하자.

 

4. sin(x)에 1.0을 더해보자. 모든 값이 0.0에서 2.0 사이인지 확인해보자.

 

5. sin(x)에 2.0을 곱해보자. 진폭의 크기가 두 배로 늘어나는지 확인해보자.

 

6. sin(x)의 절대값(abs())을 계산해보자.

 

7. sin(x)의 결과 중 소수부(fract())를 추출해보자.

 

8. sin(x)의 결과에서 더 큰 정수(ceil()와 더 작은 정수(floor())를 더하면 1과 -1 값의 digital wave가 발생한다.


이외의 유용한 함수들

 

아래에 있는 것들은 유용하게 자주 쓰이는 함수들이다. 하나씩 주석을 풀면서 결과를 관찰해보길 바란다.

y = mod(x,0.5); // return x modulo of 0.5
//y = fract(x); // return only the fraction part of a number
//y = ceil(x);  // nearest integer that is greater than or equal to x
//y = floor(x); // nearest integer less than or equal to x
//y = sign(x);  // extract the sign of x
//y = abs(x);   // return the absolute value of x
//y = clamp(x,0.0,1.0); // constrain x to lie between 0.0 and 1.0
//y = min(0.0,x);   // return the lesser of x and 0.0
//y = max(0.0,x);   // return the greater of x and 0.0

 


Advance shaping functions

 

Golan Levin은 복잡한 shaping function에 대해 문서로 훌륭하게 정리해냈다. GLSL로 포팅하는 것은 자신만의 코드 리소스를 구축하기 위한 매우 현명한 방법이다.

 

Polynomial Shaping Functions: www.flong.com/archive/texts/code/shapers_poly

Exponential Shaping Functions: www.flong.com/archive/texts/code/shapers_exp

Circular & Elliptical Shaping Functions: www.flong.com/archive/texts/code/shapers_circ

Bezier and Other Parametric Shaping Functions: www.flong.com/archive/texts/code/shapers_bez

 

Iñigo Quiles는 유용한 함수(http://www.iquilezles.org/www/articles/functions/functions.htm)들을 많이 가지고 있다. 이 아티클(http://www.iquilezles.org/www/articles/functions/functions.htm)을 읽고 GLSL로 작성해보길 바란다.

 

아래의 이미지를 참고해 직접 그려보길 바란다. 연습문제라고 생각하면 되며 구현 능력을 향상시켜줄 것이다.

 

'Graphics > GLSL' 카테고리의 다른 글

06. Shapes  (0) 2022.01.02
05. Colors  (0) 2021.12.31
03. Uniforms, gl_FragCoord  (0) 2021.12.30
02. Hello world!  (0) 2021.12.29
01. Shader란 무엇인가?  (0) 2021.12.29

댓글