Skip to main content
민트라

셰이더 입문자의 좌절과 극복 - GLSL 첫 한 달

"셰이더를 배우면 뭐든 할 수 있다"는 말을 들었습니다. Three.js로 기본적인 것은 만들 수 있었지만, 정말 멋진 효과들은 전부 커스텀 셰이더였습니다. 그래서 배우기로 했는데, 생각보다 험난했습니다.

1주차: 완전한 혼란 #

셰이더 코드를 처음 봤을 때의 느낌:

void main() {
  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

"이게 뭐지? C언어 같기도 하고..."

첫 번째 벽: 개념 이해 #

가장 어려웠던 건 GPU의 사고방식을 이해하는 것이었습니다.

CPU 방식 (익숙함):
for (let i = 0; i < pixels.length; i++) {
  pixels[i] = calculateColor(i);
}

GPU 방식 (낯설음):
모든 픽셀이 동시에 "나는 무슨 색이지?" 계산
서로의 존재를 모름

"픽셀마다 독립적으로 실행된다"는 개념이 처음에는 와닿지 않았습니다.

두 번째 벽: 디버깅 #

console.log가 없습니다. 값을 확인하려면 색상으로 출력해야 합니다.

// 값을 확인하고 싶을 때
void main() {
  float value = someCalculation();
  // console.log(value); 불가능!

  // 대신 색상으로 출력
  gl_FragColor = vec4(value, 0.0, 0.0, 1.0);
  // 빨간색 강도로 값을 확인
}

에러 메시지도 암호 같았습니다.

ERROR: 0:12: 'assign' : cannot convert from 'float' to 'highp 3-component vector of float'

2주차: 작은 성공들 #

UV 좌표 이해 #

드디어 UV 좌표가 뭔지 이해했습니다.

varying vec2 vUv;

void main() {
  // vUv.x: 0.0 (왼쪽) ~ 1.0 (오른쪽)
  // vUv.y: 0.0 (아래) ~ 1.0 (위)

  // 수평 그라데이션
  gl_FragColor = vec4(vUv.x, 0.0, 0.0, 1.0);
}

화면에 빨간 그라데이션이 나타났을 때의 기쁨!

첫 번째 효과: 물결 #

유튜브 튜토리얼을 따라 물결 효과를 만들었습니다.

uniform float uTime;
varying vec2 vUv;

void main() {
  float wave = sin(vUv.x * 10.0 + uTime) * 0.5 + 0.5;
  gl_FragColor = vec4(vec3(wave), 1.0);
}

"드디어 뭔가 움직인다!" 작은 성공이지만 큰 동기부여가 됐습니다.

3주차: 본격적인 학습 #

Book of Shaders 발견 #

The Book of Shaders를 발견했습니다. 게임체인저였습니다.

인터랙티브 에디터에서 코드를 수정하면 바로 결과가 보입니다. 이해가 안 되던 개념들이 하나씩 풀렸습니다.

핵심 함수들 #

자주 쓰는 함수들을 정리했습니다.

// mix: 선형 보간
vec3 color = mix(colorA, colorB, 0.5); // 50% 섞기

// step: 계단 함수
float s = step(0.5, vUv.x); // x < 0.5면 0, 아니면 1

// smoothstep: 부드러운 전환
float s = smoothstep(0.4, 0.6, vUv.x); // 0.4~0.6 사이에서 부드럽게 변화

// fract: 소수점 부분
float f = fract(vUv.x * 10.0); // 0~1 반복 패턴

// mod: 나머지
float m = mod(vUv.x, 0.1); // 주기적 패턴

패턴 만들기 #

반복 패턴을 만드는 법을 배웠습니다.

// 체크무늬
float check = step(0.5, fract(vUv.x * 10.0)) *
              step(0.5, fract(vUv.y * 10.0));

// 원
float dist = distance(vUv, vec2(0.5));
float circle = 1.0 - step(0.3, dist);

// 격자
float grid = step(0.95, fract(vUv.x * 10.0)) +
             step(0.95, fract(vUv.y * 10.0));

4주차: 실전 적용 #

프로젝트에 셰이더 적용 #

진행 중인 프로젝트에 커스텀 셰이더를 적용해봤습니다.

목표: 데이터 히트맵 시각화

// Vertex Shader
varying vec2 vUv;
attribute float aValue;
varying float vValue;

void main() {
  vUv = uv;
  vValue = aValue;

  vec3 pos = position;
  pos.z = aValue * 2.0; // 값에 따라 높이 변화

  gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}

// Fragment Shader
varying vec2 vUv;
varying float vValue;

void main() {
  // 값에 따른 색상 (파랑 → 빨강)
  vec3 cold = vec3(0.0, 0.0, 1.0);
  vec3 hot = vec3(1.0, 0.0, 0.0);
  vec3 color = mix(cold, hot, vValue);

  gl_FragColor = vec4(color, 1.0);
}

Three.js에서 사용:

const material = new THREE.ShaderMaterial({
  uniforms: {
    uTime: { value: 0 }
  },
  vertexShader: vertexShaderCode,
  fragmentShader: fragmentShaderCode
});

// 커스텀 attribute 추가
const values = new Float32Array(vertexCount);
// ... 데이터 채우기
geometry.setAttribute('aValue', new THREE.BufferAttribute(values, 1));

문제 해결 과정 #

처음에는 화면이 까맣게 나왔습니다. 디버깅 과정:

  1. UV 확인: gl_FragColor = vec4(vUv, 0.0, 1.0); → OK
  2. varying 확인: gl_FragColor = vec4(vValue, 0.0, 0.0, 1.0); → 전부 검정
  3. attribute 확인: JavaScript에서 값이 제대로 들어가는지 확인 → 문제 발견!
// 잘못된 코드
geometry.setAttribute('aValue', new THREE.BufferAttribute(values, 3));
// 정정: 1개 컴포넌트
geometry.setAttribute('aValue', new THREE.BufferAttribute(values, 1));

배운 것들 #

실수 방지 체크리스트 #

☐ float에 .0 붙이기 (5 → 5.0)
☐ vec3/vec4 타입 맞추기
☐ varying은 양쪽 셰이더에 선언
☐ attribute 컴포넌트 수 확인
☐ uniform 이름 일치 확인

유용한 도구들 #

  1. Shadertoy: 다른 사람의 셰이더 분석
  2. GLSL Sandbox: 빠른 프로토타이핑
  3. VSCode GLSL Extension: 문법 하이라이팅, 에러 검출

학습 자료 추천 #

  1. The Book of Shaders: 기초부터 차근차근
  2. Inigo Quilez 블로그: 고급 기법
  3. Bruno Simon Three.js Journey: 실전 적용

한 달 후 소감 #

솔직히 아직 초보입니다. 노이즈 함수, 레이마칭 같은 고급 주제는 여전히 어렵습니다.

하지만 이제 Shadertoy에서 다른 사람 코드를 보면 "아, 이 부분은 이런 원리구나" 하고 어느 정도 이해가 됩니다.

가장 큰 변화는 "이건 셰이더로 해야 해"라는 판단이 가능해진 것입니다. 성능이 필요한 시각 효과는 셰이더가 답이라는 걸 알게 됐습니다.

셰이더 학습을 고민하는 분들께: 처음 2주가 가장 힘듭니다. 거기만 넘기면 조금씩 재미있어집니다. The Book of Shaders로 시작하세요. 정말 잘 만들어진 자료입니다.