프래그먼트 셰이더(Fragment Shader): 픽셀에 색을 입히는 예술.

242025년 08월 14일4

정점 셰이더가 3D 모델의 뼈대를 잡는 건축가라면, 프래그먼트 셰이더는 그 뼈대 위를 채색하는 화가였다. 워킹 그룹의 논의는 이제 화면의 가장 작은 단위, ‘픽셀(Pixel)’의 색상을 결정하는 이 두 번째 셰이더로 옮겨갔다.

프래그먼트 셰이더의 역할은 명확하게 정의되었다.

입력(Input): 화면에 그려질 하나의 픽셀에 대한 정보.
출력(Output): 해당 픽셀의 최종 색상(RGBA 값).
역할: 3D 모델이 차지하는 모든 픽셀에 대해 각각 한 번씩 실행된다.

“정점 셰이더와 마찬가지로, 프래그먼트 셰이더 역시 지극히 자기중심적입니다.”
AMD의 그래픽스 전문 엔지니어가 설명을 시작했다. “자신이 지금 칠해야 할 픽셀 외에, 주변 픽셀에 대한 정보는 전혀 알 수 없습니다. 이 제약 덕분에 GPU는 수백만 개의 픽셀을 동시에, 병렬적으로 처리할 수 있는 겁니다.”

문제는 ‘어떤 정보’를 바탕으로 색을 결정할 것인가였다. 단순히 모든 픽셀을 똑같은 빨간색으로 칠하는 것은 의미가 없었다. 사실적인 그래픽을 위해서는 더 많은 정보가 필요했다.

여기서 ‘varying’ 이라는 특별한 종류의 변수가 등장했다.
varying은 정점 셰이더에서 프래그먼트 셰이더로 데이터를 넘겨주기 위한 다리 역할을 했다.

예를 들어, 3D 모델의 각 정점이 고유한 색상 값을 가지고 있다고 가정해보자. (예: 정점 A는 빨강, 정점 B는 초록, 정점 C는 파랑)

  1. 개발자는 이 정점 색상 데이터를 attribute로 정점 셰이더에 전달한다.
  2. 정점 셰이더는 이 색상 값을 varying 변수에 그대로 복사해서 담는다.
  3. GPU의 래스터라이저(Rasterizer)는 이 세 정점을 연결한 삼각형 내부의 픽셀들을 계산하면서, 각 픽셀의 위치에 따라 정점들의 varying 값을 부드럽게 보간(Interpolation) 한다. 즉, 정점 A에 가까운 픽셀은 빨간색에 가까운 값을, 정점 B와 C의 중간에 있는 픽셀은 초록과 파랑이 섞인 청록색에 가까운 값을 갖게 된다.
  4. 마지막으로, 프래그먼트 셰이더는 이렇게 보간된 색상 값을 입력으로 받아, 최종 픽셀 색상으로 출력한다.

varying 메커니즘을 통해, 정점 단위의 정보가 픽셀 단위의 정보로 자연스럽게 변환될 수 있었다.

이 모든 것을 종합한, 기본적인 프래그먼트 셰이더의 코드는 놀랍도록 간결한 형태를 띨 수 있었다.

// GLSL (OpenGL Shading Language) 코드

// 정점 셰이더로부터 보간된 값을 받아옴
varying vec4 v_color;

void main() {
    // 최종 픽셀 색상 = 보간된 색상
    gl_FragColor = v_color;
}

여기서 gl_FragColor는 프래그먼트 셰이더가 반드시 값을 할당해야 하는 특별한 내장 출력 변수였다. 이 변수에 담긴 RGBA 값이 바로 해당 픽셀의 최종 색상이 되는 것이다.

“이게 전부가 아닙니다.”
블라디미르가 회의에 활기를 불어넣었다. “만약 v_color 대신, 조명의 방향과 물체 표면의 법선 벡터(Normal Vector)를 varying으로 넘겨준다면 어떻게 될까요? 프래그먼트 셰이더 안에서 간단한 빛 계산 공식을 적용하면, 입체감을 표현하는 음영 효과를 만들어낼 수 있습니다.”

그의 말처럼, 프래그먼트 셰이더의 진정한 힘은 단순한 색상 보간을 넘어, 복잡한 조명 계산과 텍스처 매핑(Texture Mapping)을 수행할 수 있다는 데 있었다. 텍스처 이미지에서 특정 좌표의 색상을 읽어와 픽셀에 입히고, 여기에 조명 효과를 더하면 사실적인 질감을 가진 3D 모델이 탄생하는 것이다.

이제 개발자들은 브라우저에 단지 ‘이 물체는 금속 재질이야’라고 알려주는 것이 아니라, ‘빛이 이 각도로 들어오면, 이 픽셀의 반사율과 분산율은 이러하니, 최종 색상은 이렇게 계산해서 칠해라’고 직접 가르칠 수 있게 되었다.

워킹 그룹은 이 구조를 WebGL 1.0의 프래그먼트 셰이더 표준으로 확정했다. 정점 셰이더가 형태를 만드는 뼈대를 제공하고, 프래그먼트 셰이더가 그 위에 색과 질감을 입히는 살을 붙이는 완벽한 한 쌍이 탄생한 것이다.

이 두 개의 셰이더를 통해, 웹 개발자들은 비로소 3D 그래픽 렌더링의 핵심적인 두 단계를 자신의 코드로 완벽하게 통제할 수 있는, 전례 없는 권한을 부여받게 될 터였다. 남은 질문은 단 하나였다. 이 강력한 셰이더 프로그램들을 어떤 언어로 작성해야 하는가?