테마 선택

📚 지식 노트

AI·하드웨어·주변기기·게임·컴퓨터 시스템·이론 컴퓨터 과학·수학·개발과 운영·보안·응용 분야에 대해 알아 두면 좋은 내용을 정리한 노트다. 위에서 분야를 고르고 아래에서 노트를 고른다.

컴퓨터 그래픽스

브라우저·게임·그래픽 편집기의 렌더링 파이프라인을 비교하고, 3차원 장면이 정점 변환·래스터화·셰이딩을 거쳐 픽셀이 되는 과정을 따라간다. 래스터화와 레이 트레이싱을 작은 예로 직접 계산한다.

목차 (13)
  1. 브라우저·게임·그래픽 툴의 렌더링 파이프라인
  2. 좌표 공간과 변환
  3. 래스터화: 삼각형을 픽셀로
  4. 깊이 버퍼: 무엇이 앞에 있나
  5. 컬링과 LOD: 안 보일 것은 그리지 않는다
  6. 셰이딩: 빛과 재질
  7. 텍스처와 밉맵
  8. 그림자
  9. 레이 트레이싱
  10. 현대 파이프라인과 셰이더
  11. 안티에일리어싱
  12. 흔한 오해
  13. 더 공부할 자료

브라우저·게임·그래픽 툴의 렌더링 파이프라인

렌더링은 문서·장면·도형 같은 표현을 이미지로 만드는 과정이다. 렌더링 파이프라인은 그 과정의 작업과 중간 결과가 연결되는 구조다. 브라우저의 DOM 처리, 게임 엔진의 한 프레임, GPU API의 그래픽 파이프라인은 서로 다른 범위를 가리킨다. 모든 앱이 같은 단계나 같은 순서로 화면을 만든다는 뜻은 아니다.

브라우저·게임·2D 편집기·3D 제작 도구의 입력, 처리, 결과를 비교한 렌더링 파이프라인브라우저DOM · CSS레이아웃 · 페인트래스터 · 합성화면 표시게임장면 갱신 · 컬링명령 준비GPU 렌더 패스화면 표시2D 편집기레이어 · 경로마스크 · 필터이미지 합성미리보기 · 파일3D 제작 도구장면 평가렌더 엔진노드 합성미리보기 · 파일역할을 비교한 개념도다. 구현에 따라 병렬화·생략·반복·분기가 있다.
브라우저·게임·2D 편집기·3D 제작 도구에서 입력이 표시·파일로 이어지는 역할 비교. 각 줄은 설명용 개념 모델이며 실제 프로그램에는 분기·여러 렌더 패스·캐시와 병렬 실행이 있다.
대상주요 입력과 중간 결과성능을 볼 때의 초점
웹 브라우저DOM·CSS → 계산된 스타일·배치 → 그리기 명령 → 픽셀 타일·합성 프레임첫 화면, 입력 응답, 스크롤과 화면의 안정성
게임 엔진게임 상태·장면 → 가시 물체·명령 버퍼 → 깊이·재질·조명 버퍼 → 표시할 프레임프레임 시간과 변동, 입력에서 화면까지의 지연
2D 그래픽 편집기문서의 레이어·경로·이미지 → 마스크·필터·합성 결과 → 화면 미리보기 또는 출력 이미지붓질·확대·필터의 응답, 이미지 크기와 중간 버퍼 메모리
3D 제작 도구장면·카메라·재질 → 렌더 엔진의 이미지·패스 → 합성 노드의 결과 → 미리보기 또는 파일편집 중 응답과 최종 출력의 품질·표본 수·시간

브라우저: 레이아웃도 그래픽을 준비하는 작업이다

브라우저는 글자의 줄바꿈과 상자 위치부터 계산해야 한다. 페인트가 그리기 명령을 기록하면 래스터화가 픽셀을 만들고, 합성이 준비된 결과를 배치한다. Canvas·WebGL·WebGPU의 결과도 페이지에 함께 표시되지만 캔버스 안의 장면은 앱이나 그래픽 API가 관리한다. 웹 개발 노트의 브라우저 파이프라인과 리플로우·레이아웃 시프트 구분에서 더 자세히 다룬다.

게임: 한 프레임의 패스와 GPU 내부 단계를 구별한다

게임 상태 갱신·가시 물체 선별·그리기 명령 준비 뒤 GPU가 깊이·그림자·조명·후처리·UI 같은 여러 렌더 패스를 처리한다. 각 패스의 그리기 호출 안에서 정점 처리·래스터화·프래그먼트 처리 같은 GPU 그래픽 파이프라인이 실행된다. 컴퓨트나 광선 추적 작업은 별도 경로를 쓸 수 있다. GPU의 래스터화 단계를 프레임 전체와 같은 것으로 보면 안 된다. Vulkan 파이프라인 명세가 API의 단계 구분을 정의한다.

렌더 패스는 단순한 한 줄보다 의존성 그래프에 가깝다. 어떤 패스가 어떤 버퍼·텍스처를 읽고 쓰는지 알아야 순서·자원 수명·동기화를 정할 수 있다. Unreal Engine의 Rendering Dependency Graph가 그 예다. 구체적인 패스와 중간 이미지는 게임 개발 노트의 한 프레임 해부로 이어진다.

CPU와 GPU도 반드시 한 프레임씩 서로 기다리며 일하지 않는다. 자원 복사본과 동기화를 갖추면 CPU가 다음 프레임의 자료를 쓰는 동안 GPU는 이전 프레임을 그릴 수 있다. 다만 아직 읽는 버퍼를 덮어쓰면 안 되고, 큐를 길게 쌓으면 처리량과 별개로 입력 지연이 커질 수 있다. Metal의 CPU·GPU 동기화 예제가 버퍼를 여러 개 두는 이유를 보여 준다.

그래픽 툴: 편집용 미리보기와 최종 출력은 목적이 다르다

2D 편집기의 문서는 이미 완성된 픽셀 하나만이 아니다. 레이어·벡터 경로·마스크·필터를 보존한 채 결과를 합성하고, 확대율·화면 색에 맞춰 미리보기를 만든다. 바뀐 부분의 중간 결과만 다시 만드는 캐시는 응답에 유리하지만, 결과 이미지와 중간 버퍼의 메모리가 필요하다. 벡터·블렌딩·색 공간 자체는 그래픽 기초 노트가 다룬다.

3D 제작 도구는 편집 중 응답과 최종 이미지의 품질을 따로 조절한다. 뷰포트가 언제나 별도의 간단한 엔진인 것은 아니며 최종 렌더와 같은 엔진을 다른 설정으로 쓸 수도 있다. Blender의 Viewport Render 설명은 현재 뷰포트를 이미지로 뽑는 기능과 최종 렌더의 차이를 보여 준다. 렌더한 이미지·패스는 다시 Blender Compositor 같은 노드 그래프에서 색 보정·마스크·합성을 거쳐 파일로 저장할 수 있다.

프레임 버퍼가 완성되는 것과 모니터에 표시되는 것도 다른 단계다. 표시할 이미지를 제출한 뒤에는 윈도 시스템·디스플레이 합성·표시 타이밍이 관여한다. Vulkan의 WSI에서는 이를 화면 표시용 이미지와 presentation의 관계로 다룬다. 파일 출력은 디스플레이 대신 이미지·영상 인코딩으로 이어질 수 있다. 앱이 무엇을 입력받아 어떤 결과를 내고 어디를 다시 계산하는지부터 보면 같은 "렌더링"이라는 말에 속지 않는다.

좌표 공간과 변환

픽셀·색 공간·블렌딩 같은 2D 기초와 GPU가 한 프레임을 그리는 큰 순서는 그래픽 기초 노트에 있다. 여기서는 3D 장면이 어떻게 그 픽셀이 되는지를 들여다본다. 게임 엔진 관점의 렌더링 기법(지연 렌더링, 포스트 프로세싱)은 게임 개발 › 렌더링 노트가 다룬다.

3D 모델은 삼각형의 꼭짓점(정점) 목록이다. 정점 좌표는 여러 좌표 공간을 차례로 지난다. 모델링할 때의 자기 기준(모델 공간) → 장면 안의 자리(월드 공간) → 카메라 기준(뷰 공간) → 원근을 넣은 클립 공간 → 정규화 장치 좌표(NDC) → 화면 픽셀. 각 단계는 행렬 곱이다.

3차원 점인데 4×4 행렬을 쓰는 이유는 동차 좌표 때문이다. 점 (x, y, z)를 (x, y, z, 1)로 쓰면 회전·크기 변환과 평행 이동을 모두 행렬 곱 하나로 나타낼 수 있고, 여러 변환을 미리 곱해 행렬 하나로 합칠 수 있다. 방향 벡터(법선 등)는 w = 0으로 써서 이동의 영향을 받지 않게 한다. 투영 행렬은 이 w 자리에 카메라와의 거리를 넣어 두는데, 나중에 x, y를 w로 나누면 먼 것이 작아지는 원근이 생긴다.

정점 하나가 여섯 좌표 공간을 지나며 바뀌는 좌표를 단계별로 보여 주는 그림① 모델 공간(1, 1, 1, 1)물체 자기 기준 좌표② 월드 공간(2, 1, −5, 1)× 모델 행렬 M③ 뷰 공간(2, 0.5, −5, 1)× 뷰 행렬 V④ 클립 공간(2, 0.5, 4.04, 5)× 투영 행렬 P⑤ NDC(0.4, 0.1, 0.808)÷ w (원근 나눗셈)⑥ 화면(560, 360)× 뷰포트 변환정점 셰이더가 내보내는 것은 ④ 클립 좌표
1 / 6

정육면체의 꼭짓점 (1, 1, 1, 1). 마지막 1은 동차 좌표 w다 — w = 1인 점만 이동 행렬의 마지막 열을 받아 움직인다(방향 벡터는 w = 0이라 이동하지 않는다).

정점 변환. 정점 셰이더는 ①→④를 행렬 곱 한 번(P·V·M)으로 하고, ⑤·⑥은 GPU 고정 기능이 한다.

행렬 곱은 순서가 중요하다. 열 벡터에 왼쪽으로 곱하는 관례에서는 P·V·M·v처럼 오른쪽부터 적용된다. "돌리고 옮기기"와 "옮기고 돌리기"는 결과가 다르다. 또 깊이 범위가 OpenGL은 −1~1, Direct3D·Vulkan·Metal·WebGPU는 0~1이고, y축과 손잡이 방향(오른손·왼손 좌표)도 API마다 달라 투영 행렬을 옮겨 쓸 때 자주 틀린다.

래스터화: 삼각형을 픽셀로

화면 좌표를 얻은 삼각형은 래스터화로 픽셀 단위의 조각(fragment)이 된다. 픽셀 중심이 삼각형 안에 있는지는 세 변에 대한 모서리 함수로 판정한다. 모서리 함수 E(p)는 변 a→b와 점 p로 만든 평행사변형의 넓이(2D 외적)로, 부호가 p가 변의 왼쪽인지 오른쪽인지를 말해 준다. 세 변 모두 같은 쪽이면 안이다. 픽셀마다 독립적인 덧셈·곱셈뿐이라 GPU가 수천 픽셀을 동시에 검사하기 좋다.

모서리 함수 값을 삼각형 전체 넓이로 나누면 무게중심 좌표(α, β, γ)가 된다. 픽셀이 각 꼭짓점에 얼마나 가까운지를 나타내는 비율(합 1)이라, 꼭짓점마다 붙은 색·텍스처 좌표·법선·깊이를 이 비율로 섞으면 픽셀의 값이 나온다. 원근이 있으면 화면에서 선형으로 섞으면 틀리므로, 값을 w로 나눠 섞은 뒤 다시 1/w의 보간값으로 나누는 원근 보정 보간을 한다.

8×8 픽셀 격자 위 삼각형의 안쪽 픽셀을 한 줄씩 판정하고, 한 픽셀의 무게중심 좌표를 구하는 단계 그림ABCE_AB(p), E_BC(p), E_CA(p)세 부호가 같으면 p는 삼각형 안1번째 줄 → 안쪽 0칸2번째 줄 → 안쪽 2칸3번째 줄 → 안쪽 5칸4번째 줄 → 안쪽 5칸5번째 줄 → 안쪽 4칸6번째 줄 → 안쪽 3칸7번째 줄 → 안쪽 2칸8번째 줄 → 안쪽 0칸픽셀 (3, 3)의 무게중심 좌표α = E_BC(p) ÷ 넓이 = 0.372β = E_CA(p) ÷ 넓이 = 0.311γ = E_AB(p) ÷ 넓이 = 0.317깊이 = 0.37×0.2 + 0.31×0.5 + 0.32×0.8= 0.483점 = 픽셀 중심(파랑 안, 빨강 밖)
1 / 10

삼각형 ABC를 8×8 픽셀 격자에 그린다. 픽셀 중심이 삼각형 안에 있는지는 세 변의 모서리 함수 E(p) = (b − a) × (p − a)의 부호로 판정한다. 셋 다 같은 부호면 안이다.

래스터화. 픽셀 중심 64개 가운데 21개가 삼각형 안이다. 경계가 계단처럼 보이는 것이 에일리어싱이다.

두 삼각형이 변을 공유하면 변 위의 픽셀을 두 번 칠하거나 하나도 안 칠할 수 있다. GPU는 "위쪽·왼쪽 변 위의 픽셀만 그 삼각형 것"으로 치는 top-left 규칙으로 정확히 한 번만 칠한다.

깊이 버퍼: 무엇이 앞에 있나

삼각형은 아무 순서로나 그려지는데, 화면에는 가장 가까운 면이 보여야 한다. 깊이 버퍼(Z 버퍼)는 픽셀마다 지금까지 그린 것 중 가장 가까운 깊이를 적어 둔다. 새 조각이 오면 적힌 값보다 가까울 때만 색과 깊이를 덮어쓴다. 정렬 없이 픽셀 단위로 가림이 풀린다. 다만 반투명한 물체는 뒤의 색과 섞어야 하므로 불투명한 것을 먼저 그리고, 반투명한 것은 뒤에서 앞 순서로 정렬해 따로 그린다.

두 면의 픽셀별 깊이와, 깊이 버퍼가 픽셀마다 더 가까운 면을 남긴 결과0 가까움1 멂빨간 면(먼저 그림)파란 면(나중에 그림)100.6010.6020.2030.3240.4450.5660.6070.8080.929결과칸 안 숫자 = 깊이 버퍼에 남은 값(처음엔 모두 1). 색 = 그 픽셀에 남은 면.
깊이 버퍼. 빨간 면을 먼저 그렸어도 파란 면이 더 가까운 픽셀(3~6)은 파란 면이 덮고, 빨간 면이 더 가까운 7은 그대로 남는다.

원근 투영의 깊이 값은 거리에 비례하지 않고 1/거리에 비례한다. near 1, far 100이면 거리 5에서 깊이 값이 벌써 0.81에 이른다. 거리 범위의 앞쪽 4%에 깊이 값의 81%를 쓰는 셈이라, 먼 곳에서는 두 면의 깊이가 같은 값으로 뭉개져 서로 번갈아 비치는 Z 파이팅이 생긴다. near를 너무 작게 잡지 않는 것이 가장 쉬운 처방이고, 요즘 엔진은 깊이를 거꾸로(가까운 곳 1, 먼 곳 0) 저장해 부동소수점의 촘촘한 0 근처를 먼 곳에 쓰는 reverse-Z를 많이 쓴다.

거리 1~100에서 깊이 버퍼 값의 곡선. 가까운 쪽에서 급히 올라가 먼 쪽은 1 근처에 몰린다011100카메라와의 거리깊이 값거리 → 깊이 값2 → 0.5055 → 0.80810 → 0.90950 → 0.990near 1, far 100값 ∝ 1 − near ÷ 거리
near 1, far 100일 때 거리별 깊이 버퍼 값. 곡선이 앞쪽에서 거의 다 올라가 버린다.

컬링과 LOD: 안 보일 것은 그리지 않는다

깊이 버퍼는 가려진 면을 픽셀 단위로 버리지만, 그때는 이미 정점 처리와 래스터화 비용을 치른 뒤다. 그래서 그리기 전에 안 보일 것을 덩어리째 걸러 낸다. 이것이 컬링(culling)이다.

  • 뒷면 컬링: 닫힌 물체의 뒤쪽 면은 화면에서 꼭짓점 순서가 거꾸로 감긴다. 래스터화 단계가 이 감기 방향(OpenGL 기본은 반시계 방향이 앞면)으로 뒷면을 버린다. 정육면체는 어느 각도에서도 많아야 세 면만 보이므로 프래그먼트 셰이더 실행이 절반 넘게 준다(LearnOpenGL의 면 컬링).
  • 절두체 컬링: 카메라가 보는 범위는 near·far·위·아래·왼쪽·오른쪽 평면 여섯 장으로 둘러싼 잘린 피라미드(절두체)다. 물체를 구나 상자 같은 단순한 경계 볼륨으로 감싸 두고, 여섯 평면 모두의 안쪽에 걸치는지 검사해 바깥 물체는 그리기 호출 자체를 하지 않는다(LearnOpenGL의 절두체 컬링). 많은 물체를 검사할 때는 컴퓨트 셰이더로 GPU에서 한꺼번에 하기도 한다.
  • 가림 컬링(occlusion culling): 화면 안에 있어도 큰 벽 뒤에 숨은 물체는 보이지 않는다. 앞 프레임이나 큰 가림막만 먼저 그린 깊이로 물체의 경계 볼륨이 완전히 가려졌는지 확인해 걸러 낸다.
  • LOD(level of detail): 멀리 있어 화면에서 몇 픽셀밖에 안 되는 물체는 삼각형이 적은 간단한 모델로 바꿔 그린다. 텍스처의 밉맵과 같은 생각을 형상에 적용한 것이다. 메시 셰이더 절의 Nanite는 이 단계를 삼각형 묶음 단위로 자동화했다.

셰이딩: 빛과 재질

픽셀의 색은 표면의 방향(법선 N), 빛이 오는 방향 L, 눈이 있는 방향 V로 정한다. 가장 단순한 램버트 확산은 빛을 고르게 퍼뜨리는 무광 표면의 밝기를 N·L(두 단위 벡터 사이 각도의 코사인)로 둔다. 빛이 비스듬할수록 같은 빛이 넓은 면에 퍼져 어두워진다는 뜻이다. 눈의 위치와는 상관이 없다.

반짝이는 하이라이트는 눈 방향에 따라 달라진다. 퐁(Phong, 1975)은 빛을 법선에 대해 거울 반사한 R과 눈 방향 V가 가까울수록 밝게, (R·V)ⁿ으로 계산한다. 지수 n이 크면 작고 날카로운 하이라이트가 된다. 블린-퐁(Blinn-Phong, 1977)은 R 대신 L과 V의 가운데 방향 H를 구해 (N·H)ⁿ을 쓴다. 반사 벡터를 계산하지 않아 싸고, 비스듬한 각도에서 더 자연스러워 오랫동안 실시간 그래픽의 기본이었다. H와 N 사이 각도는 R과 V 사이 각도의 약 절반이라, 비슷한 하이라이트를 얻으려면 지수를 4배쯤 키운다.

표면의 한 점에서 법선, 빛, 눈, 반사, 중간 벡터와 그것으로 계산한 확산·반사광 세기가로선 = 표면 · N 법선 · L 빛 · R 반사 · V 눈 · H 중간NLRVHN과 L 사이 50°확산 N·L = 0.643R과 V 사이 30°퐁 (R·V)^16 = 0.100N과 H 사이 15°블린-퐁 (N·H)^64 = 0.109H는 각도가 반이라 지수를 약 4배로잡아야 비슷한 크기의 반짝임이 된다
한 점에서의 셰이딩 벡터. 같은 장면에서 퐁(n = 16)과 블린-퐁(n = 64)의 반사광 세기가 비슷하게 나온다.
구의 왼쪽 끝에서 오른쪽 끝까지 확산광, 퐁 반사광, 블린-퐁 반사광의 세기 곡선01왼쪽 끝가운데오른쪽 끝하이라이트 x = 0.38확산(램버트)퐁 n = 16블린-퐁 n = 64빛: 오른쪽 위 45°눈: 정면최종 색 ≈ 물체 색 × (환경광 + 확산) + 빛 색 × 반사광
구의 가로 단면을 따라 잰 세기. 확산은 빛을 정면으로 받는 오른쪽에서 가장 밝고, 반사광은 법선이 빛과 눈의 가운데를 보는 한 점 근처에만 좁게 생긴다.

퐁 계열은 보기 좋게 맞춘 근사라, 조명이 바뀌면 재질이 어색해지고 에너지 보존도 안 된다. 요즘 게임과 영화는 물리 기반 렌더링(PBR)을 쓴다. 표면을 눈에 안 보이는 작은 거울 조각(미세면)의 모음으로 보고, Cook–Torrance 꼴의 반사 함수(BRDF) = D·F·G ÷ (4·(N·L)·(N·V))로 계산한다.

  • D(법선 분포): 미세면 중 H 방향을 향한 비율. 거칠기(roughness)가 크면 넓게 퍼져 하이라이트가 크고 흐려진다. GGX 분포가 표준이다.
  • F(프레넬): 비스듬히 볼수록 반사가 세지는 현상. 물웅덩이가 멀리서는 거울 같은 이유다. Schlick 근사 F₀ + (1 − F₀)(1 − V·H)⁵로 계산한다.
  • G(기하 감쇠): 미세면끼리 서로 가리고 그림자 지는 비율.
  • 재질은 기본색(albedo), 금속성(metallic), 거칠기 세 값으로 거의 다 표현된다. 금속은 확산이 없고 반사에 색이 있으며, 비금속은 반사가 약 4%로 색이 없다. 2012년 디즈니의 원칙 기반 BRDF와 2013년 언리얼 엔진 4의 발표 이후 업계 표준이 됐다.

빛 계산은 선형 공간에서 해야 한다. 모니터는 입력값에 비례해 밝아지지 않고 대략 2.2제곱 곡선을 따르며, 사람이 화면을 보며 고른 색과 sRGB 색 텍스처에는 이 곡선이 이미 들어 있다. 그래서 색 텍스처는 읽을 때 선형으로 풀고(sRGB 텍스처 형식이 자동으로 해 준다), 노멀 맵·거칠기처럼 색이 아닌 데이터는 처음부터 선형으로 둔다. 감마는 모든 계산이 끝난 맨 마지막에 한 번만 다시 건다. 중간에 걸면 이후 계산이 모두 틀어진다(LearnOpenGL의 감마 보정). 감마의 뜻은 그래픽 기초 노트에, 1보다 밝은 값을 모니터 범위로 누르는 톤 매핑은 렌더링 노트의 한 프레임 해부에 있다.

텍스처와 밉맵

정점마다 색을 주는 것만으로는 세부를 표현할 수 없어 표면에 이미지를 입힌다. 정점에 이미지 안의 위치인 UV 좌표(0~1)를 붙이고, 래스터화가 픽셀마다 UV를 보간하면, 프래그먼트 셰이더가 그 자리의 텍셀(텍스처의 픽셀)을 읽는다. 색뿐 아니라 법선(노멀 맵), 거칠기, 금속성도 텍스처로 준다. 노멀 맵은 평평한 면에 울퉁불퉁한 법선을 줘서 삼각형을 늘리지 않고 요철이 있어 보이게 한다.

  • 필터링: UV가 텍셀 사이에 떨어지면 가장 가까운 텍셀을 쓰거나(최근접, 픽셀 아트처럼 각짐), 둘레 4개를 거리 비율로 섞는다(쌍선형).
  • 밉맵(Williams, 1983): 멀리 있는 면은 화면 픽셀 하나에 텍셀 수십 개가 들어와, 그중 하나만 읽으면 반짝이는 노이즈(에일리어싱)가 생긴다. 미리 반씩 줄인 사본을 1×1까지 만들어 두고, 픽셀 하나에 들어오는 텍셀 수에 맞는 단계를 읽는다. 두 단계 사이도 섞으면 삼선형 필터링이다.
  • 비등방성 필터링: 비스듬히 누운 바닥은 픽셀이 한 방향으로만 길게 텍스처를 덮는다. 밉맵은 정사각형을 가정해 이런 곳을 뭉개므로, 긴 방향을 따라 여러 번 읽어 섞는다(최대 16×).
  • 텍스처 압축: BC(데스크톱)·ASTC(모바일) 같은 블록 압축은 4×4 텍셀을 고정 크기로 줄여, GPU가 풀지 않은 채로 아무 자리나 바로 읽는다.
256×256 텍스처의 밉맵 사슬과, 화면 크기에 따라 밉 단계를 고르는 계산0256112826433241658… 1×1 (단계 8)단계 번호와 한 변 크기메모리: 원본 + ¼ + ¹⁄₁₆ + … = 원본의 1.333배1024² 텍스처를 화면 128픽셀 폭에 → 픽셀당 텍셀 8개 → 단계 log₂8 = 3
밉맵 사슬. 줄어든 사본을 모두 더해도 원본의 약 33%만 더 든다. 화면 픽셀 하나에 텍셀 2ⁿ개가 들어오면 n단계를 읽는다.

그림자

래스터화는 "이 픽셀에서 빛이 보이는가"를 직접 알 수 없다. 가장 흔한 해법은 그림자 맵(Williams, 1978)이다. 먼저 빛의 자리에서 장면을 깊이만 그려 둔다. 그다음 카메라로 그릴 때 각 점을 빛의 좌표로 옮겨, 빛까지 거리가 그림자 맵에 적힌 값보다 멀면 무언가에 가려진 것이니 그림자다.

빛에서 본 깊이 지도와 세 점의 그림자 판정그림자 맵(빛에서 가장 가까운 면까지 거리)1010666101010빛떠 있는 판P₁P₂P₃P₁: 빛까지 10, 지도 6→ 더 멂: 그림자P₂: 빛까지 10, 지도 10→ 같음: 빛을 받음P₃: 빛까지 6, 지도 6→ 같음: 빛을 받음비교할 때 작은 bias를 더해, 면이 자기 자신을 가리는 오판을 막는다
그림자 맵. 판 아래 바닥 P₁은 빛까지 거리가 지도에 적힌 값(판까지 거리)보다 멀어 그림자다. 판 윗면 P₃과 빈 바닥 P₂는 두 값이 같아 빛을 받는다.
  • 그림자 여드름(acne): 지도 해상도와 정밀도 한계로 면이 자기 자신을 가린다고 판정해 줄무늬가 생긴다. 비교할 때 작은 bias를 더하는데, 너무 크면 그림자가 물체에서 떨어져 뜨는 피터 팬 현상이 생긴다.
  • 계단 경계: 지도의 텍셀이 화면에서 크게 보이면 그림자 경계가 각진다. 주변 여러 텍셀을 비교해 평균하는 PCF로 부드럽게 하고, 가리는 물체와의 거리에 따라 번짐을 바꾸는 PCSS로 반그림자를 흉내 낸다.
  • 계단식 그림자 맵(CSM): 넓은 야외에서는 카메라 가까운 곳에 촘촘한 지도, 먼 곳에 성긴 지도를 여러 장 둔다.
  • 요즘 GPU에서는 빛 쪽으로 광선을 쏘아 가림을 직접 확인하는 레이 트레이싱 그림자도 실시간으로 쓴다(다음 절).

레이 트레이싱

래스터화는 "삼각형마다 어느 픽셀을 덮는가"를 묻고, 레이 트레이싱은 거꾸로 "픽셀마다 광선이 무엇에 맞는가"를 묻는다. 눈에서 픽셀을 지나는 광선 o + t·d를 쏘고 가장 가까운 교차점을 찾는다. 구라면 광선 식을 구의 방정식에 넣어 t에 대한 2차 방정식을 풀면 된다. 판별식이 음수면 빗나간 것이고, 양수면 작은 근이 들어가는 점, 큰 근이 나오는 점이다. 교차점에서 그림자 광선(빛 쪽), 반사 광선, 굴절 광선을 다시 쏘면 거울·유리·정확한 그림자가 자연스럽게 나온다(Whitted, 1980).

왼쪽에서 오른쪽으로 쏜 광선이 구와 두 점에서 만나는 그림과 2차 방정식 풀이중심 c (5, 0), r = 2눈 ot = 3.27t = 6.73법선 N|o + t·d − c|² = r²→ t² + 2b·t + c' = 0b = (o − c)·d = −5c' = |o − c|² − r² = 22판별식 b² − c' = 3음수면 빗나감, 0이면 스침t = −b ± √3 = 3.27, 6.73가까운 점 (3.27, 1)N = (점 − c) ÷ r = (−0.87, 0.5)
광선–구 교차. 판별식이 양수라 두 점에서 만나고, 가까운 점의 법선이 셰이딩에 쓰인다.

장면에 삼각형이 수백만 개면 광선마다 모두와 교차를 검사할 수 없다. 물체들을 상자로 감싸고 상자를 다시 큰 상자로 묶은 트리, BVH(경계 볼륨 계층)를 만들어, 광선이 맞지 않는 상자 안은 통째로 건너뛴다. 검사가 삼각형 수에 대해 로그에 가깝게 준다.

경로 추적(path tracing)은 카지야(Kajiya, 1986)의 렌더링 방정식, 즉 "한 점에서 나가는 빛 = 스스로 내는 빛 + 들어오는 모든 빛 × 반사 함수 × cosθ를 반구 전체로 적분한 것"을 몬테카를로로 푼다. 반사 방향을 무작위로 골라 광선을 몇 번씩 튕기고, 픽셀마다 여러 경로를 평균한다. 간접광·부드러운 그림자·색 번짐이 공짜로 나와 영화 렌더링의 표준이 됐다. 대가는 노이즈다. 무작위 표본 평균의 오차는 표본 수의 제곱근에 반비례하므로, 노이즈를 반으로 줄이려면 표본이 4배 필요하다.

픽셀당 표본 수 1부터 1024까지 몬테카를로 추정의 상대 오차. 로그 눈금에서 직선으로 줄어든다100%10%1%57.3129.8414.0167.2643.42561.71024픽셀당 표본 수(spp)상대 오차실제로 잰 오차1/√N표본 4배 → 오차 ½1024 spp에도 1.7%그래서 실시간은 몇 spp만쏘고 노이즈 제거기로 메운다
몬테카를로 노이즈. 고르게 밝은 하늘 아래 바닥 한 점의 밝기(정답 π)를 무작위 방향으로 추정할 때, 표본 수를 4배로 늘릴 때마다 오차가 반으로 준다.
  • 하드웨어: 2018년 NVIDIA 튜링부터 GPU에 BVH 순회와 광선–삼각형 교차를 전담하는 회로(RT 코어)가 들어갔고, 같은 해 DirectX 레이 트레이싱(DXR), 2020년 Vulkan 레이 트레이싱 확장이 나왔다. 지금은 AMD·인텔·애플·모바일 GPU도 레이 트레이싱 회로를 갖고 있다. GPU 구조는 GPU 노트에 있다.
  • 노이즈 제거: 실시간에서는 픽셀당 1~2개 경로밖에 못 쏜다. 시간(앞 프레임)과 공간(이웃 픽셀)의 표본을 재활용해 거르는 노이즈 제거기(SVGF, NVIDIA OptiX·DLSS Ray Reconstruction 같은 신경망 방식)가 나머지를 메운다. 좋은 광원 표본을 픽셀끼리 나눠 쓰는 ReSTIR가 표본 효율을 크게 높였다.
  • 섞어 쓰기: 대부분의 게임은 화면은 래스터화로 그리고 반사·그림자·전역 조명에만 광선을 쓰는 하이브리드다. 2023년 무렵부터 일부 게임은 조명 전체를 경로 추적하는 모드를 넣었다.

현대 파이프라인과 셰이더

GPU 파이프라인 중 일부는 셰이더라는 작은 프로그램으로 직접 짠다. 정점 셰이더는 정점마다 한 번 돌아 클립 좌표와 넘길 값을 내고, 프래그먼트(픽셀) 셰이더는 래스터화된 조각마다 돌아 색을 낸다. 클리핑·래스터화·깊이 테스트·블렌딩은 하드웨어 고정 기능이다. 셰이더는 HLSL·GLSL·MSL·WGSL 같은 언어로 쓰고, 수천 개가 같은 코드를 다른 데이터로 동시에 실행한다. 분기가 갈리면 같은 묶음의 스레드가 양쪽을 모두 거쳐 느려진다.

정점 입력부터 프레임 버퍼까지 그래픽 파이프라인 단계와, 별도로 도는 컴퓨트 셰이더정점 입력버퍼에서 정점 읽기정점 셰이더좌표 변환테셀레이션·지오메트리(선택)클리핑·래스터화픽셀로 쪼개기프래그먼트 셰이더픽셀 색 계산출력 병합깊이 테스트·블렌딩프레임 버퍼화면에 보냄컴퓨트 셰이더버퍼·텍스처를 자유롭게 읽고 씀컬링·후처리·입자·물리·노이즈 제거·AI 추론래스터화를 거치지 않는 계산색칠 = 셰이더(직접 프로그래밍) · 흰 칸 = 고정 기능
그래픽 파이프라인. 색칠한 단계가 셰이더로 짜는 곳이다. 컴퓨트 셰이더는 이 흐름 밖에서 GPU를 범용 병렬 계산기로 쓴다.
  • 컴퓨트 셰이더: 래스터화와 상관없이 버퍼를 읽고 쓰는 일반 병렬 계산. 보이지 않는 물체 걸러내기(컬링), 입자, 후처리 블러, 노이즈 제거에 쓴다.
  • 메시 셰이더: 정점 입력·테셀레이션·지오메트리 단계를 컴퓨트 셰이더 같은 단계 하나로 바꿔, 작은 삼각형 묶음(meshlet) 단위로 GPU가 직접 만들고 걸러 낸다. 언리얼 엔진 5의 Nanite처럼 수십억 삼각형급 장면을 다루는 방식이 이런 흐름 위에 있다.
  • 저수준 API: 예전 API는 드라이버가 상태와 메모리를 알아서 관리해 편하지만 CPU 부담이 컸다. 새 API는 명령 버퍼를 여러 스레드에서 미리 기록하고, 메모리 배치와 동기화를 앱이 직접 맡는다. 코드가 길어지는 대신 그리기 호출의 CPU 비용이 크게 준다.
API나온 해플랫폼특징
OpenGL / OpenGL ES1992여러 OS, 옛 모바일드라이버가 상태를 대신 관리하는 오래된 API. 새 기능은 더 이상 크게 늘지 않는다.
Direct3D 122015윈도, Xbox명령 버퍼·메모리·동기화를 앱이 직접 관리하는 저수준 API. DXR 레이 트레이싱과 메시 셰이더를 가장 먼저 넣었다.
Metal2014macOS, iOS애플 기기 전용 저수준 API. 애플 실리콘의 타일 기반 GPU에 맞춰져 있다.
Vulkan2016윈도, 리눅스, 안드로이드Khronos의 크로스 플랫폼 저수준 API. 설정이 길지만 제어가 세밀하다. 레이 트레이싱은 확장으로 들어왔다.
WebGPU2023웹 브라우저Vulkan·D3D12·Metal 위에 얹은 웹 표준. 컴퓨트 셰이더를 쓸 수 있고 셰이더 언어는 WGSL이다.

WebGPU는 크롬(2023)에 이어 2025년에 사파리와 파이어폭스(윈도)도 기본으로 켜, 브라우저에서도 컴퓨트 셰이더를 쓸 수 있게 됐다. 이 사이트의 3D 뷰어처럼 웹에서 3D를 그리는 도구는 아직 WebGL(OpenGL ES 기반)을 쓰는 것이 많다.

안티에일리어싱

픽셀 중심 하나만 보고 칠하면 비스듬한 경계가 계단이 된다. 연속인 모양을 띄엄띄엄 표본으로 잴 때 생기는 에일리어싱이다(소리의 앨리어싱과 같은 원리, 신호 처리 노트). 해결은 픽셀 하나를 여러 번 재는 것이다.

  • SSAA(슈퍼샘플링): 화면을 2~4배 크게 그려 줄인다. 가장 정확하지만 셰이딩 비용도 그만큼 든다.
  • MSAA: 픽셀 안의 여러 자리(4×, 8×)에서 삼각형이 덮는지와 깊이만 재고, 셰이더는 픽셀당 한 번만 돌린다. 덮인 표본 비율로 색을 섞어 경계를 부드럽게 한다. 텍스처 안이나 셰이더가 만든 무늬의 에일리어싱은 못 고치고, 지연 렌더링과는 잘 맞지 않는다.
  • FXAA·SMAA: 다 그린 이미지에서 경계를 찾아 흐리는 후처리. 싸지만 글자 같은 세부도 함께 흐려진다.
  • TAA: 매 프레임 카메라를 픽셀보다 작게 흔들어(지터) 다른 자리를 재고, 움직임 벡터로 앞 프레임과 맞춰 섞는다. 시간에 걸쳐 슈퍼샘플링하는 셈이라 요즘 게임의 기본이다. 빠른 움직임에서 잔상과 흐림이 생긴다.
  • 업스케일링: DLSS·FSR·XeSS는 TAA를 확장해 낮은 해상도로 그린 뒤 여러 프레임의 표본으로 높은 해상도를 복원한다. 신경망을 쓰는 방식이 많다.
같은 비스듬한 모서리를 중앙 표본 1개, 4× MSAA, 실제 넓이로 칠한 6×3 픽셀 비교표본 1개(픽셀 중앙)4× MSAA실제 덮인 넓이오차 합 1.54 · 계단오차 합 0.43 · ¼ 단위기준빨간 선 = 모서리(아래가 도형 안) · 점 = 표본 자리(진한 점이 안쪽)
같은 경계를 세 방식으로 칠했다. 중앙 표본 하나는 0 아니면 1이라 계단이 되고, 4× MSAA는 실제 넓이에 ¼ 단위로 가까워진다.

흔한 오해

  • “깊이 버퍼가 있으니 그리는 순서는 상관없다” — 불투명한 면은 결과가 같지만, 뒤에서 앞으로 그리면 가려질 픽셀에도 셰이더를 돌려 시간이 든다. 반투명한 면은 순서가 틀리면 색 자체가 틀린다.
  • “노멀 맵이 모양을 바꾼다” — 바뀌는 것은 빛 계산에 쓰는 법선뿐이다. 삼각형은 그대로라 옆에서 본 윤곽과 그림자의 모양은 평평한 면 그대로다.
  • “셰이더에서 색을 그냥 더하고 곱하면 된다” — 대부분의 색 텍스처는 감마가 걸린 sRGB 값이다. 선형 값으로 풀지 않고 계산하면 빛이 겹치는 곳이 지나치게 밝거나 탁해진다(셰이딩 절).

더 공부할 자료

코드를 짜 보며 배우려면 Ray Tracing in One Weekend와 LearnOpenGL이 좋은 시작점이고, 기법의 전체 지도는 Real-Time Rendering, 물리적으로 정확한 렌더링의 이론은 PBR 책이 맡는다.

자료내용링크
Real-Time Rendering, 4판 (Akenine-Möller 외)실시간 렌더링 기법을 거의 빠짐없이 정리한 표준 참고서. 기법마다 원 논문으로 가는 길잡이다.Routledge
Physically Based Rendering, 4판 (Pharr · Jakob · Humphreys)경로 추적 렌더러 pbrt의 코드 전체를 설명하며 물리 기반 렌더링을 가르친다. 온라인에 무료로 공개돼 있다.pbr-book.org
Ray Tracing in One Weekend 시리즈 (Shirley 외)주말 동안 작은 레이 트레이서를 직접 짜 보는 무료 소책자 세 권. 광선–구 교차부터 재질과 BVH까지.raytracing.github.io
LearnOpenGL창 띄우기부터 조명·그림자·PBR·후처리까지 코드로 따라 하는 무료 강좌.learnopengl.com
Scratchapixel래스터화·투영 행렬·레이 트레이싱을 수식과 코드로 바닥부터 설명한다.scratchapixel.com
Filament 물리 기반 렌더링 문서 (Google)모바일 렌더러 Filament가 쓰는 PBR 수식(미세면 BRDF, 조명 단위)을 유도와 함께 정리했다.Google
A trip through the Graphics Pipeline 2011 (Giesen)API 호출부터 드라이버, 래스터화, 깊이 테스트까지 GPU 안에서 실제로 일어나는 일을 연재로 풀었다.블로그