후처리
고친 사람 github-actions[bot]
후처리는 다 그린 화면 그림에 효과를 한 번 더 입힙니다. 완성된 그림 한 장만 읽어서 흐림이나 색감을 손봅니다. 사진 편집이나 데이터 분석에서도 본 작업을 마친 결과를 다듬는 일을 후처리라고 부릅니다. 이 항목은 그래픽스의 후처리를 다룹니다.
쉽고 빠른 이해
후처리는 게임이나 3차원 화면을 다 그린 다음 그 그림 전체를 보정합니다. 밝은 불빛 둘레를 번지게 하거나 화면 전체의 색감을 차갑게 바꾸는 일이 그런 예입니다.
이런 효과는 물체를 하나씩 그리는 도중에는 넣기 어렵습니다. 불빛 번짐은 이웃한 점들을 함께 봐야 합니다. 그런데 그리는 도중에는 옆에 무엇이 올지 아직 모릅니다.
- 장면을 화면이 아니라 이미지 한 장에 먼저 그립니다
- 화면의 모든 점마다 그 이미지를 읽어 새 색을 계산합니다
- 효과가 여럿이면 앞 효과의 결과를 다음 효과가 읽습니다. 마지막 결과를 화면에 내보냅니다
대가는 화면 크기에 비례하는 계산입니다. 효과 하나마다 화면 전체를 한 번씩 읽고 씁니다. 그림 한 장만 보므로 물체 뒤에 가려진 것은 알 수 없습니다.
상세
이 절은 후처리가 무엇을 받아 무엇을 내놓는지, 그리고 그 일이 그래픽 장치 위에서 어떻게 도는지를 다룹니다. 그림을 흑백으로 바꾸는 효과 하나는 셰이더 코드로 직접 봅니다. 뒤의 소절은 효과마다 드는 비용과 효과를 잇는 순서를 봅니다.
사진을 찍은 뒤 편집 앱에서 필터를 고르면 사진 전체의 색감이 한 번에 바뀝니다. 찍었던 사람과 풍경을 다시 불러 세울 필요가 없습니다. 찍힌 사진 한 장만 있으면 됩니다.
렌더링은 3차원 장면의 물체들을 계산해 화면에 보일 2차원 그림으로 바꾸는 일입니다. 후처리는 이 렌더링이 끝난 그림을 입력으로 받습니다. 그리고 효과를 입힌 그림을 내놓습니다. 이 단계에서는 물체의 모양이나 위치를 더 이상 쓰지 않습니다.
이 일은 GPU(Graphics Processing Unit, 그래픽 처리 장치)가 맡습니다. GPU 는 화면의 수많은 점에 같은 계산을 한꺼번에 돌리도록 만든 계산 장치입니다. 후처리는 화면의 모든 점에 같은 계산을 하는 일이라 GPU 에 잘 맞습니다.
다 그린 뒤에야 할 수 있는 효과
어떤 효과는 한 점의 색을 정하려고 둘레의 점을 봐야 합니다. 밝은 불빛 둘레가 번져 보이게 하는 블룸이 그렇습니다. 불빛 옆의 점은 원래 무슨 색이었든 불빛의 밝기를 조금 나눠 받아야 합니다.
물체를 그리는 도중에는 이 일을 못 합니다. 물체는 하나씩 차례로 그려집니다. 지금 그리는 점 옆에 나중에 무엇이 그려질지 아직 모릅니다.
다 그린 그림이 있으면 이 문제가 사라집니다. 모든 점의 최종 색이 이미 정해져 있습니다. 어느 점이든 이웃을 마음대로 읽을 수 있습니다.
일을 한 곳에 모으는 이점도 있습니다. 화면 전체의 색감을 바꾸는 계산을 물체마다 넣으면 물체를 그리는 프로그램을 전부 고쳐야 합니다. 후처리로 빼면 그 계산을 한 곳에서 한 번만 합니다.
그림을 이미지에 받아 두기
화면은 작은 점이 격자로 늘어선 것입니다. 그 점 하나가 픽셀입니다.
화면에 나갈 픽셀 색을 담아 두는 메모리를 프레임버퍼라고 부릅니다. 모니터에 보이는 색은 이 메모리에서 나옵니다. 후처리가 없으면 렌더링 결과를 이 프레임버퍼에 곧장 적습니다.
후처리를 하려면 다 그린 그림을 한 번 다시 읽어야 합니다. 그래서 장면을 화면 대신 따로 마련한 이미지에 그립니다. 그림을 받는 이 이미지를 렌더 타깃이라고 부릅니다. 화면에 안 보이는 곳에 그린다는 뜻으로 이 방식을 오프스크린 렌더링이라고도 합니다.
다 그린 렌더 타깃은 다음 단계에서 텍스처로 읽습니다. 텍스처는 좌표를 주면 그 위치의 색을 꺼내 주는 이미지입니다. 원래는 물체 표면에 무늬를 입히려고 쓰는 기능입니다. 후처리는 이 읽기 기능을 빌려 방금 그린 그림을 다시 읽습니다.
화면을 덮는 사각형 하나
GPU 는 물체를 삼각형 단위로 그립니다. 삼각형이 덮는 픽셀마다 작은 프로그램을 한 번씩 돌려 색을 정합니다. 이 프로그램이 프래그먼트 셰이더입니다.
후처리는 이 구조를 빌립니다. 화면을 꽉 채우는 사각형 하나를 그립니다. 사각형이 화면 전체를 덮으므로 프래그먼트 셰이더가 화면의 모든 픽셀에서 한 번씩 돕니다. 이 사각형을 흔히 풀스크린 쿼드라고 부릅니다.
프래그먼트 셰이더는 자기 픽셀 위치로 렌더 타깃을 읽습니다. 읽은 색으로 새 색을 계산해 내놓습니다. 백엔드 코드로 옮기면 「픽셀 위치를 받아 새 색을 돌려주는 함수」를 화면의 모든 픽셀에 한 번씩 부르는 셈입니다.
아래는 그림을 흑백으로 바꾸는 프래그먼트 셰이더의 핵심 세 줄입니다. 셰이더 언어 GLSL(OpenGL Shading Language)로 적었습니다.
t 는 앞 단계가 그린 렌더 타깃입니다. p 는 지금 픽셀의 위치입니다. texture() 는 그 위치의 색을 빨강·초록·파랑 세 값으로 꺼냅니다. color 는 이 픽셀의 결과 색입니다.
vec3 c = texture(t, p).rgb; // 0.6 0.3 0.0
float g = (c.r+c.g+c.b)/3.0; // 0.3
color = vec4(g, g, g, 1.0); // 회색
주황빛 픽셀 하나가 들어와 세 값의 평균 0.3 이 됐습니다. 그 값을 빨강·초록·파랑 세 칸에 똑같이 넣어 회색을 만들었습니다. 네 번째 값 1.0 은 불투명하다는 표시입니다. 이 함수가 모든 픽셀에서 돌면 화면 전체가 흑백이 됩니다.
프래그먼트 셰이더 대신 컴퓨트 셰이더로 돌리기도 합니다. 컴퓨트 셰이더는 삼각형을 그리지 않고 GPU 에 계산만 맡기는 프로그램입니다. 픽셀마다 한 번씩 부른다는 점은 같습니다.
효과마다 읽는 범위
효과는 한 픽셀의 새 색을 정하려고 무엇을 읽느냐로 갈립니다. 자기 픽셀 하나만 읽는 효과가 있습니다. 둘레 픽셀을 여럿 읽는 효과도 있습니다. 이 범위가 비용을 정합니다.
색만으로 모자란 효과도 있습니다. 초점이 맞은 거리만 또렷하게 두고 나머지를 흐리려면 픽셀마다 카메라에서 얼마나 먼지를 알아야 합니다. 이 거리를 픽셀마다 적어 둔 이미지가 깊이 버퍼입니다. 렌더링 때 함께 만들어 두었다가 후처리에서 같이 읽습니다.
| 효과 | 한 픽셀을 정하려고 읽는 것 | 하는 일 |
|---|---|---|
| 색 보정 | 자기 픽셀 하나 | 색감과 대비를 바꾼다 |
| 비네팅 | 자기 픽셀 하나와 화면 위치 | 화면 가장자리를 어둡게 한다 |
| 가우시안 블러 | 둘레 픽셀 여럿 | 이웃 색을 섞어 화면을 흐린다 |
| 블룸 | 둘레의 밝은 픽셀 여럿 | 밝은 곳의 빛을 둘레로 번지게 한다 |
| 피사계 심도 | 둘레 픽셀과 깊이 | 초점 밖 물체를 흐린다 |
| 모션 블러 | 움직인 방향의 픽셀 여럿 | 빠르게 움직인 것을 끌린 듯 흐린다 |
| 후처리 안티에일리어싱 | 둘레 픽셀 여럿 | 계단진 경계를 부드럽게 한다 |
표의 가운데 칸이 넓을수록 비싼 효과입니다. 색 보정은 픽셀마다 한 번 읽으면 끝납니다. 반경이 넓은 가우시안 블러는 픽셀마다 수십 번을 읽습니다.
여러 효과를 잇는 순서
효과는 대개 여럿을 잇습니다. 이 소절은 효과 사이에 이미지를 어떻게 넘기는지, 그리고 순서가 왜 결과를 바꾸는지를 봅니다.
한 효과가 같은 이미지를 읽으면서 동시에 쓰면 곤란합니다. 이웃 픽셀을 읽었는데 그 픽셀이 이미 새 값으로 바뀌어 있을 수 있습니다. 그래서 읽는 이미지와 쓰는 이미지를 따로 둡니다.
흔한 방법은 이미지 둘을 번갈아 쓰는 것입니다. 첫 효과는 이미지 A 를 읽어 이미지 B 에 씁니다. 둘째 효과는 B 를 읽어 A 에 씁니다. 효과가 몇 개든 이미지는 둘이면 됩니다.
이 방식을 핑퐁 버퍼라고 부릅니다. 탁구공처럼 두 이미지 사이를 오간다는 뜻입니다.
아래 그림은 효과 둘을 이은 예입니다. 맨 끝에는 HUD(Head-Up Display, 헤드업 디스플레이)를 얹습니다. HUD 는 점수판이나 메뉴처럼 화면에 겹쳐 띄우는 글자와 아이콘입니다.
flowchart TD
S["장면 그리기"] --> A1["이미지 A"]
A1 --> E1["효과 1 · 흐림"]
E1 --> B1["이미지 B"]
B1 --> E2["효과 2 · 색 보정"]
E2 --> A2["이미지 A"]
A2 --> U["HUD 얹기"]
U --> O["화면"]
HUD 는 대개 후처리가 다 끝난 뒤에 얹습니다. 먼저 얹으면 글자까지 흐려지거나 색이 바뀝니다.
밝기를 다루는 순서도 결과를 바꿉니다. 조명 계산은 햇빛과 그늘을 함께 담으려고 화면이 낼 수 있는 범위보다 넓은 밝기 값을 쓰기도 합니다. 이 넓은 밝기 범위를 HDR(High Dynamic Range, 넓은 명암 범위)이라고 합니다.
화면은 그 범위를 다 못 냅니다. 그래서 후처리 끝 무렵에 넓은 밝기를 화면이 낼 수 있는 범위로 눌러 담습니다. 이 일이 톤 매핑입니다.
블룸처럼 밝기에 기대는 효과는 대개 톤 매핑보다 앞에서 돕니다. 눌러 담은 뒤에는 어느 불빛이 얼마나 밝았는지가 뭉개지기 때문입니다.
맨 끝에는 색 공간을 바꿉니다. 색 공간은 색을 숫자로 적는 약속입니다. 조명 계산은 빛의 세기에 비례하는 숫자로 합니다. 빛이 두 배 세면 숫자도 두 배가 됩니다.
모니터는 사람 눈에 맞춘 숫자를 기대합니다. 사람 눈은 밝은 쪽보다 어두운 쪽의 차이를 더 잘 알아챕니다. 그래서 한정된 숫자 범위를 어두운 밝기 쪽에 더 촘촘히 나눠 씁니다. 이 색 공간이 sRGB(standard RGB, 표준 빨강·초록·파랑 — RGB 는 Red Green Blue)입니다.
빛의 세기에 비례하는 숫자를 sRGB 숫자로 바꾸는 변환을 감마 보정이라고 부릅니다. 후처리 셰이더가 마지막에 직접 하기도 합니다.
프레임버퍼를 sRGB 형식으로 만들어 두면 셰이더가 이 변환을 안 해도 됩니다. GPU 가 값을 적는 순간 변환을 대신 합니다. 이런 프레임버퍼를 sRGB 프레임버퍼라고 합니다.
후처리의 대가
후처리 비용은 장면에 물체가 몇 개인지와 거의 상관없습니다. 픽셀 수와 효과가 픽셀마다 읽는 횟수로 정해집니다. 화면의 가로와 세로가 각각 두 배가 되면 픽셀이 네 배라 비용도 네 배 가까이 됩니다.
그래서 성능이 모자라면 후처리 효과부터 줄입니다. 게임 그래픽 설정의 「모션 블러」·「블룸」 끄기 선택지가 그런 예입니다. 비싼 흐림은 화면을 작게 줄인 이미지에서 돌린 뒤 다시 키우기도 합니다. 이렇게 이미지를 줄이는 일을 다운샘플링이라고 합니다.
효과를 이을수록 메모리와 주고받는 양이 늘어납니다. 효과 하나마다 화면 크기의 이미지를 한 번 읽고 한 번 씁니다. GPU 가 메모리와 주고받을 수 있는 양의 한도를 메모리 대역폭이라고 합니다.
효과가 많으면 계산보다 이 한도에 먼저 닿기도 합니다. 그래서 자기 픽셀만 읽는 효과 여럿은 셰이더 하나로 합쳐 한 번에 돌리기도 합니다.
후처리는 그림 한 장에 남은 정보만 봅니다. 물체 뒤에 가려진 배경은 그림에 없습니다. 초점 밖 물체를 흐리면 그 가장자리에서 뒤쪽 배경이 비쳐 보여야 합니다. 그 배경을 읽을 수 없어 경계에 어색한 자국이 남기도 합니다.
경계를 다듬는 안티에일리어싱도 같은 한계를 겪습니다. 픽셀 한 칸보다 작은 모양은 그림에 이미 남아 있지 않습니다. 그림만 보고 경계를 짐작해 흐리므로 글자 같은 잔무늬까지 흐려질 수 있습니다.
다른 분야의 후처리
후처리라는 이름은 그래픽스 밖에서도 흔히 씁니다. 뜻의 뼈대는 같습니다. 본 작업이 끝난 결과를 받아 한 번 더 다듬습니다. 무엇을 다듬는지만 분야마다 다릅니다.
| 분야 | 본 작업 | 후처리가 하는 일 |
|---|---|---|
| 사진과 영상 편집 | 촬영 | 색 보정 · 잘라내기 · 잡음 줄이기 |
| 수치 해석과 시뮬레이션 | 방정식 풀이 | 결과 수치를 그래프나 색 지도로 보이기 |
| 머신러닝 | 모델의 예측 | 겹친 예측 걸러내기 · 낮은 점수 버리기 |
| 음향 | 녹음 | 잡음 제거 · 음량 맞추기 |
본 작업 앞에서 입력을 다듬는 일은 전처리라고 부릅니다. 머신러닝에서 학습 데이터의 크기를 맞추거나 빈 값을 채우는 일이 전처리입니다. 두 말은 본 작업을 가운데 두고 앞뒤로 짝을 이룹니다.
관련 항목
후처리 단계에서 입히는 효과
블룸 · 톤 매핑 · 색 보정 · 컬러 그레이딩 · 가우시안 블러 · 피사계 심도 · 모션 블러 · 비네팅 · 색수차 · 필름 그레인 · 렌즈 플레어 · 갓 레이 · 화면 공간 앰비언트 오클루전 · 화면 공간 반사
후처리로 하는 안티에일리어싱 기법
안티에일리어싱 · 후처리 안티에일리어싱 · FXAA · SMAA · MLAA · 시간적 안티에일리어싱
후처리가 읽고 쓰는 이미지와 버퍼
렌더 타깃 · 오프스크린 렌더링 · 프레임버퍼 · 프레임버퍼 객체 · 텍스처 · 색 버퍼 · 깊이 버퍼 · G 버퍼 · 핑퐁 버퍼
후처리를 돌리는 GPU 프로그램과 그리기 방식
셰이더 · 프래그먼트 셰이더 · 컴퓨트 셰이더 · GLSL · HLSL · 풀스크린 쿼드 · 풀스크린 트라이앵글 · 렌더 패스
후처리가 속하는 렌더링 흐름
렌더링 · 렌더 파이프라인 · 그래픽스 파이프라인 · 래스터화 · 포워드 렌더링 · 디퍼드 셰이딩 · 렌더 그래프 · HUD
후처리 끝에서 밝기를 화면 숫자로 바꾸는 변환
HDR · 선형 색 공간 · sRGB · 감마 보정 · sRGB 프레임버퍼 · 색 관리
후처리 비용을 정하는 요인과 줄이는 기법
해상도 · 메모리 대역폭 · 필레이트 · 다운샘플링 · 분리 가능 필터 · GPU
그래픽스 밖에서 후처리와 맞물리는 처리 기법
전처리 · 이미지 처리 · 컨볼루션 · 비최대 억제 · 유한 요소 해석
다른 이름: post-processing · postprocessing · post-process · 포스트 프로세싱 · 포스트프로세싱