Graphics

셰이더 함수 정리

jinlee0310 2024. 11. 24. 23:30

패스트 캠퍼스에서 수강한 강의 내용 중 셰이더 함수에 대해 정리하였다.

우선 무작정 따라해볼 수 있도록 glsl에서 사용되는 함수들에 대해 알아볼 것이다.

개발 환경은 Vite+VanillaJS환경이다.

1. 그라데이션

precision mediump float;

varying vec2 vUv;

void main(){
  // 1. 그라데이션
  float x = vUv.x;
  float y = vUv.y;

  float col = x;

  gl_FragColor=vec4(col, col, col, 1.0);
}

vUv는 vertex shader에서 가져온 값을 의미한다.

x좌표에 따라 color의 값이 0.0부터 1.0까지 변화한다.

2. 대각선 만들기

precision mediump float;

varying vec2 vUv;

void main(){
  // 2. 대각선 그라데이션 만들기
  float x = vUv.x;
  float y = vUv.y;

  float gradient = (x + y) / 2.0;
  vec3 col = vec3(gradient);

  gl_FragColor=vec4(col, 1.0);
}

만약 사선 모양의 그라데이션을 만들고 싶다면 위와 같이 코드를 수정해주면 된다.

3. step

precision mediump float;

varying vec2 vUv;

void main(){
  // 3. step
  float x = vUv.x;
  float y = vUv.y;

  float strength = step(0.5, x); // 기준점, 변수
  vec3 col = vec3(strength);

  gl_FragColor=vec4(col, 1.0);
}

step 함수는 첫번째 인자로 기준점을 받고 두번째 인자로 변수를 받는다. 변수가 기준점을 넘지 않으면 0.0을 리턴하고 기준점을 넘으면 1.0을 리턴한다.

4. min, max

precision mediump float;

varying vec2 vUv;

void main(){
  // 4. min, max
  float x = vUv.x;
  float y = vUv.y;

  float strength = min(0.5, x);
  // float strength = max(0.5, x);
  vec3 col = vec3(strength);

  gl_FragColor=vec4(col, 1.0);
}

JavaScript의 Math.min, Math.max 함수와 같은 리턴값을 가진다.

4. min, max

precision mediump float;

varying vec2 vUv;

void main(){
  // 4. min, max
  float x = vUv.x;
  float y = vUv.y;

  float strength = min(0.5, x);
  // float strength = max(0.5, x);
  vec3 col = vec3(strength);

  gl_FragColor=vec4(col, 1.0);
}

JavaScript의 Math.min, Math.max 함수와 같은 리턴값을 가진다.

5. clamp

precision mediump float;

varying vec2 vUv;

void main(){
  // 5. clamp
  float x = vUv.x;
  float y = vUv.y;

  // 0.3 이하에서는 0.3을 리턴, 0.7 이상에서는 0.7을 리턴, 0.3 ~ 0.7에서는 x를 리턴
  float strength = clamp(x, 0.1, 0.8);
  vec3 col = vec3(strength);

  gl_FragColor=vec4(col, 1.0);
}

clamp 함수는 2개의 기준점을 가진다.x가 min값보다 작으면 min, min과 max 사이라면 x, max보다 크면 max를 리턴한다.

6. smoothstep

precision mediump float;

varying vec2 vUv;

void main(){
  // 6. smoothstep
  float x = vUv.x;
  float y = vUv.y;
  
  float strength = smoothstep(0.2, 0.8, x); // 내장 함수

  vec3 col = vec3(strength);

  gl_FragColor=vec4(col, 1.0);
}

step 함수에서 기준점을 그라데이션 처리하는 함수이다. 기준점의 간격이 늘어날수록 그라데이션 영역도 늘어난다.

7. mix

precision mediump float;

varying vec2 vUv;

void main(){
	// 7. mix
  float x = vUv.x;
  float y = vUv.y;

  vec3 green = vec3(0.0, 1.0, 0.0);
  vec3 blue = vec3(0.0, 0.0, 1.0);
  
  vec3 col = mix(green, blue, x);

  gl_FragColor = vec4(col, 1.0);
}

mix 함수는 첫번째 인자와 두번째 인자를 세번째 인자의 비율로 보간한 값을 리턴해주는 함수이다.

8. pow, sqrt

precision mediump float;

varying vec2 vUv;

void main(){
	// 8. pow, sqrt
  float x = vUv.x;
  float y = vUv.y;

  vec3 col = vec3(x);
  vec3 green=vec3(0.0, 1.0, 0.0);

  if(pow(x, 2.0) - 0.005 <= y && y <= pow(x, 2.0) + 0.005){
    col = green;
  }
  // if(sqrt(x) - 0.005 <= y && y <= sqrt(x) + 0.005){
  //   col = green;
  // }

  gl_FragColor=vec4(col, 1.0);
}

pow와 sqrt함수 역시 JavaScript의 Math.pow, Math.sqrt와 같다.

9. mod

precision mediump float;

varying vec2 vUv;

void main(){
  // 9. mod: (a % b)
  float x = vUv.x;
  float y = vUv.y;

  vec3 col = vec3(mod(x * 2.0, 1.0));

  gl_FragColor=vec4(col, 1.0);
}

mod함수는 나머지를 반환해주는 함수이다. 첫번째 인자로 들어온 값을 두번째 인자로 나눈 나머지를 반환한다.

10. fract

  • 소수점 이하의 값을 반환해주는 함수이다.

위 mod 함수는 아래 코드로도 대체할 수 있다.

precision mediump float;

varying vec2 vUv;

void main(){
  float x = vUv.x;
  float y = vUv.y;

  vec3 col = vec3(fract(x * 2.0));

  gl_FragColor=vec4(col, 1.0);
}

또한 아래 코드를 작성하면 이러한 효과를 만들 수도 있다.

precision mediump float;

varying vec2 vUv;

void main(){
  // . fract: 소수점 이하의 값을 반환
	float x = vUv.x;
  float y = vUv.y;

  // vec3 col = vec3(fract(x * y));
  // col = step(0.5, col);

  vec3 col = vec3(fract((x - 0.11) * 7.0));
  vec3 col2 = vec3(fract((y - 0.11) * 7.0));

  col = step(0.5, col) * step(0.5, col2);

  fract(0.4); // 0.4
  fract(2.3); // 0.3

  gl_FragColor=vec4(col, 1.0);
}

11. sin, cos

  • sin 함수와 cos 함수는 그래픽스에서 자주 사용되는 함수이다.

아래와 같이 코드를 작성한다.

precision mediump float;

varying vec2 vUv;

void main(){
  // 11. sin, cos
  float x = vUv.x;
  float y = vUv.y;

  vec3 col = vec3(sin(x * 1.0));
  // vec3 col = vec3(cos(x * 20.0));

  gl_FragColor=vec4(col, 1.0);
}

desmos 사이트에 가면 수학 그래프들을 그려볼 수 있다. 0과 1 사이에서 그래프를 따라 위와 같은 분포를 가진다고 생각하면 된다.

만약 그라데이션이 검은색부터 흰색까지 진행되다가 다시 검은색으로 돌아오는 그림을 그리고 싶다면 아래와 같이 코드를 작성하면 된다.

precision mediump float;

varying vec2 vUv;

void main(){
  // 11. sin, cos
  float x = vUv.x;
  float y = vUv.y;

  vec3 col = vec3(sin(x * 3.0));
  // vec3 col = vec3(cos(x * 20.0));

  gl_FragColor=vec4(col, 1.0);
}

비슷한 원리를 사용해서 코드를 아래와 같이 작성하면 다음과 같은 그림을 만들 수 있다.

11. sin, cos

  • sin 함수와 cos 함수는 그래픽스에서 자주 사용되는 함수이다.

아래와 같이 코드를 작성한다.

precision mediump float;

varying vec2 vUv;

void main(){
  // 11. sin, cos
  float x = vUv.x;
  float y = vUv.y;

  vec3 col = vec3(sin(x * 1.0));
  // vec3 col = vec3(cos(x * 20.0));

  gl_FragColor=vec4(col, 1.0);
}

desmos 사이트에 가면 수학 그래프들을 그려볼 수 있다. 0과 1 사이에서 그래프를 따라 위와 같은 분포를 가진다고 생각하면 된다.

만약 그라데이션이 검은색부터 흰색까지 진행되다가 다시 검은색으로 돌아오는 그림을 그리고 싶다면 아래와 같이 코드를 작성하면 된다.

precision mediump float;

varying vec2 vUv;

void main(){
  // 11. sin, cos
  float x = vUv.x;
  float y = vUv.y;

  vec3 col = vec3(sin(x * 3.0));
  // vec3 col = vec3(cos(x * 20.0));

  gl_FragColor=vec4(col, 1.0);
}

비슷한 원리를 사용해서 코드를 아래와 같이 작성하면 다음과 같은 그림을 만들 수 있다.

precision mediump float;

varying vec2 vUv;

void main(){
  // 11. sin, cos
  float x = vUv.x;
  float y = vUv.y;

  vec3 col = vec3(sin(x * 20.0));
  // vec3 col = vec3(cos(x * 20.0));

  gl_FragColor=vec4(col, 1.0);
}

12. abs

절대값을 반환해주는 함수이다.

precision mediump float;

varying vec2 vUv;

void main(){
  // 12. abs
  float x = vUv.x;
  float y = vUv.y;

  vec3 col = vec3(abs(cos(x * 20.0)));

  gl_FragColor=vec4(col, 1.0);
}

13. distance, length

두 정점 사이의 거리(길이)를 반환해주는 함수이다.

아래와 같이 코드를 작성해보자

precision mediump float;

varying vec2 vUv;

void main(){
  // 13. distance: 두 정점 사이의 거리
  float x = vUv.x;
  float y = vUv.y;

  float dist = distance(x, 0.5);

  vec3 col = vec3(dist);

  gl_FragColor=vec4(col, 1.0);
}

0.5에서부터 x위치까지의 거리를 반환해주어서 0.5와 가까울수록 어두운 색이고 멀어질수록 0.5와 가까운 색을 나타낸다.

precision mediump float;

varying vec2 vUv;

void main(){
  // 13. distance: 두 정점 사이의 거리
  float x = vUv.x;
  float y = vUv.y;

  float dist = distance(x, 0.5);
  dist = step(0.3, dist);

  vec3 col = vec3(dist);

  gl_FragColor=vec4(col, 1.0);
}

이 함수에 step 함수를 사용하면 0.3을 기준으로 0과 1을 반환하는 그림을 그릴 수 있다.

precision mediump float;

varying vec2 vUv;

void main(){
  // 13. distance: 두 정점 사이의 거리
  float x = vUv.x;
  float y = vUv.y;

  // float dist = distance(x, 0.5);
  float dist = distance(vec2(x, y), vec2(0.5));
  dist = step(0.3, dist);

  vec3 col = vec3(dist);

  gl_FragColor=vec4(col, 1.0);
}

강의에 나온 함수들을 설명한 것이고 더 자세히는 The Book of Shaders에 가면 더 많은 함수들을 확인할 수 있다.

이렇게 함수들만 쭉 정리해본 이유는 이 데모의 코드를 분석해보고 구현해보기 위해서이다. 다음 글에서는 해당 데모의 코드를 분석해보고 직접 구현해보겠다.