멀티샘플링
고친 사람 github-actions[bot]
멀티샘플링은 화면에 그린 도형의 테두리를 매끄럽게 다듬습니다. 픽셀 하나 안에 검사 지점을 여럿 두고 도형이 그중 몇 개를 덮는지 셉니다. 색은 픽셀마다 한 번만 계산합니다. 덮은 비율만큼 그 색을 배경과 섞습니다.
쉽고 빠른 이해
멀티샘플링은 도형 테두리에 생기는 톱니를 줄입니다. 비스듬한 선 하나를 그리면 픽셀 경계를 따라 계단이 보입니다. 그 계단 칸을 중간 색으로 칠해 부드럽게 보이게 합니다.
픽셀 한가운데 한 점만 보면 칸은 도형 안이거나 밖이거나 둘 중 하나입니다. 그래서 계단이 생깁니다. 점을 늘리면 계단이 풀립니다. 그런데 점마다 색까지 따로 계산하면 그리는 비용이 점 수만큼 불어납니다.
- 픽셀 안에 검사 지점을 넷쯤 둡니다
- 도형이 덮은 지점을 셉니다. 색은 픽셀마다 한 번만 계산해 덮인 지점에 적습니다
- 다 그린 뒤 지점들의 색을 평균 내 픽셀 색 하나로 줄입니다
대가는 메모리입니다. 지점마다 색을 따로 담습니다. 어느 도형이 앞에 있는지 가릴 거리도 지점마다 담습니다. 지점 수만큼 메모리가 늘어나는 셈입니다.
톱니가 주로 도형 테두리에서 나고 메모리에 여유가 있을 때 씁니다. 도형 안쪽 무늬가 지글거리는 것은 못 고칩니다.
상세
이 절은 멀티샘플링이 무엇을 받아 무엇을 내주는지, 왜 색 계산과 덮임 검사를 따로 하는지를 다룹니다. 비스듬한 변이 걸친 픽셀 하나를 따라가며 봅니다.
멀티샘플링은 흔히 MSAA(Multisample Anti-Aliasing, 멀티샘플 안티에일리어싱)라고 줄여 부릅니다. 넣는 것은 화면에 그릴 도형과 픽셀마다의 검사 지점 배치입니다. 나오는 것은 테두리가 부드러워진 이미지 한 장입니다.
한 점 검사가 만드는 계단
화면은 작은 칸이 격자로 늘어선 것입니다. 그 칸 하나가 픽셀입니다. 화면에 그리는 도형은 대개 삼각형 여러 개로 쪼개져 들어옵니다. 삼각형 하나를 그리려면 어느 픽셀이 삼각형 안에 드는지부터 골라야 합니다. 이 고르는 절차가 래스터화입니다.
기본 래스터화는 픽셀마다 한가운데 한 점만 봅니다. 그 점이 삼각형 안이면 픽셀을 칠하고 밖이면 안 칠합니다. 모양을 알아보려고 찍어 보는 이 점이 샘플입니다. 앞에서 검사 지점이라 부른 것과 같은 점입니다.
샘플이 하나뿐이면 픽셀은 전부 칠해지거나 전부 빠집니다. 삼각형의 변이 픽셀 한가운데를 조금만 비껴가도 결과가 뒤집힙니다. 그래서 비스듬한 변을 따라 칸이 들쭉날쭉하게 칠해집니다. 톱니 모양이 드러납니다.
이 톱니가 계단 현상입니다. 픽셀이 굵은 화면일수록 톱니 하나하나가 커서 눈에 잘 띕니다.
계단 현상은 더 넓은 문제의 한 모습입니다. 매끄러운 모양을 점 몇 개로만 찍어 보면 모양이 틀어져 보입니다. 이 왜곡을 통틀어 에일리어싱이라고 합니다.
에일리어싱을 누그러뜨리는 기법들은 안티에일리어싱으로 묶입니다. 멀티샘플링도 그중 하나입니다.
샘플을 늘리는 가장 곧은 방법
해결의 실마리는 샘플 수입니다. 픽셀 안에 샘플을 넷 두고 삼각형이 그중 셋을 덮었다면, 그 픽셀을 삼각형 색 4분의 3과 배경색 4분의 1로 섞으면 됩니다. 픽셀이 칠함과 안 칠함 두 값 대신 중간 값을 갖습니다. 그만큼 톱니가 흐려집니다.
가장 곧은 방법은 화면을 가로세로 두 배 크기로 그린 뒤, 이웃한 네 픽셀을 평균 내 원래 크기로 줄이는 것입니다. 이 방식을 슈퍼샘플링이라고 합니다.
슈퍼샘플링의 문제는 색 계산입니다. 픽셀마다 색을 계산하는 작은 프로그램을 프래그먼트 셰이더라고 합니다. 그림이 네 배로 커지면 이 프로그램도 네 배로 돕니다. 색 계산은 GPU(Graphics Processing Unit, 그래픽 처리 장치)가 한 장을 그리는 일에서 큰 몫을 차지합니다.
덮임은 샘플마다, 색은 픽셀마다
멀티샘플링은 계단이 어디에 생기는지를 봅니다. 계단은 도형의 테두리에만 생깁니다. 도형 안쪽 픽셀은 샘플 넷이 모두 덮입니다. 넷의 색도 거의 같습니다.
그래서 멀티샘플링은 두 일을 가릅니다. 도형이 어느 샘플을 덮었는지 보는 검사는 샘플마다 합니다. 색 계산은 픽셀마다 한 번만 합니다. 계산한 색 하나를 덮인 샘플에만 적어 둡니다.
한 도형이 픽셀 안의 어느 샘플을 덮었는지 적은 표시를 멀티샘플 커버리지, 줄여서 커버리지라고 합니다. 샘플이 넷이면 커버리지는 네 칸짜리 켜짐·꺼짐 표시입니다.
도형끼리 겹치면 카메라에 가까운 쪽이 보여야 합니다. 벽 앞에 상자가 놓이면 겹친 곳에는 상자가 보이는 식입니다. 이것을 가리려고 카메라까지의 거리, 곧 깊이를 픽셀마다 적어 둡니다. 그 메모리가 깊이 버퍼입니다.
새 도형이 들어오면 그 픽셀에 적힌 깊이와 견줍니다. 이 검사가 깊이 테스트입니다. 더 가까우면 색과 깊이를 새로 적습니다. 더 멀면 버립니다.
멀티샘플링에서는 깊이를 샘플마다 따로 담습니다. 깊이 테스트도 샘플마다 돕니다. 두 도형이 한 픽셀 안에서 겹치거나 교차하면 샘플마다 앞에 있는 도형이 다를 수 있기 때문입니다.
도형 하나가 픽셀 하나에 도착했을 때 겪는 일을 그리면 아래와 같습니다.
flowchart TD
A["도형이 픽셀 하나에 걸친다"] --> B["샘플마다 도형 안인지 검사한다"]
B --> C{"덮인 샘플이 하나라도 있나"}
C -->|없다| D["이 픽셀은 건너뛴다"]
C -->|있다| E["프래그먼트 셰이더로 색을 한 번 계산한다"]
E --> F["덮인 샘플마다 깊이 테스트를 한다"]
F --> G["통과한 샘플에만 그 색과 깊이를 적는다"]
색 계산을 가리키는 상자는 하나뿐입니다. 샘플이 넷이든 여덟이든 색 계산은 한 번입니다. 늘어나는 것은 샘플마다의 덮임 검사와 깊이 검사, 그리고 적어 둘 칸입니다. 두 검사는 값 하나를 견주는 일이라 색 계산보다 품이 적게 듭니다.
한 픽셀을 따라가 보기
파란 배경 위에 빨간 삼각형을 그린다고 합시다. 삼각형의 비스듬한 변이 어느 픽셀을 가로지르며 샘플 넷 중 셋을 덮었습니다. 그 픽셀의 샘플 넷에 적힌 색은 이렇습니다.
| 샘플 | 삼각형이 덮었나 | 적힌 색 |
|---|---|---|
| 1 | ✓ | 빨강 |
| 2 | ✓ | 빨강 |
| 3 | ✓ | 빨강 |
| 4 | ✗ | 파랑 · 앞서 그린 배경이 남는다 |
빨강은 프래그먼트 셰이더가 한 번 계산해 샘플 셋에 똑같이 적은 값입니다. 슈퍼샘플링이었다면 같은 빨강을 얻으려고 셰이더가 샘플마다 따로 돌았을 겁니다.
이 픽셀이 화면에 나갈 때는 넷을 평균 냅니다. 빨강 셋과 파랑 하나를 섞으니 빨강에 가까운 보랏빛이 됩니다. 테두리 픽셀들이 이렇게 중간 색을 띱니다. 그만큼 톱니가 흐려집니다.
한 장으로 줄이는 리졸브
샘플이 넷씩 담긴 이미지는 화면에 바로 내보낼 수 없습니다. 화면은 픽셀마다 색 하나만 받기 때문입니다.
그래서 다 그린 뒤 한 단계를 더 거칩니다. 픽셀마다 샘플들의 색을 평균 내 색 하나로 줄이는 단계입니다. 이것을 리졸브라고 부릅니다. 앞 소절의 보랏빛이 이 단계에서 나옵니다.
렌더 타깃은 그림을 그려 넣는 대상 메모리입니다. 멀티샘플링은 픽셀마다 샘플 여럿을 담는 렌더 타깃에 먼저 그리고, 리졸브를 거쳐 샘플이 하나인 보통 이미지로 옮깁니다.
샘플을 놓는 위치
샘플 넷을 바둑판처럼 반듯하게 놓으면 약점이 생깁니다. 거의 수평인 변이 지나갈 때 같은 줄의 두 샘플이 함께 덮이거나 함께 빠집니다. 그러면 샘플이 넷이어도 덮인 비율이 0 · 절반 · 전부 세 가지로만 갈립니다.
그래서 흔히 격자를 살짝 비틀어, 가로로 봐도 세로로 봐도 샘플이 서로 다른 줄에 서게 놓습니다. 샘플 수는 보통 2 · 4 · 8 중에서 고릅니다. 많을수록 중간 값의 가짓수가 늘어납니다.
메모리 비용과 고치지 못하는 계단
첫째 대가는 메모리입니다. 샘플이 넷이면 색과 깊이를 담을 칸이 네 배로 늘어납니다. 가로 1920 · 세로 1080 짜리 화면에서 한 픽셀에 4바이트를 쓰면 색만 해도 한 장이 8메가바이트 남짓입니다. 샘플이 넷이면 30메가바이트를 넘습니다.
칸이 늘면 읽고 쓰는 양도 늘어납니다. 그만큼 메모리 대역폭을 더 씁니다. 색 계산은 아꼈습니다. 메모리 쪽 비용은 샘플 수를 따라갑니다.
둘째 한계는 도형 안쪽입니다. 안쪽 무늬의 지글거림은 그대로 남습니다. 색 계산 한 번이 픽셀 한가운데 한 점만 보기 때문입니다. 멀리 깔린 바둑판 무늬 바닥이 번쩍이는 것이 그렇습니다.
멀리 있는 바닥에서는 픽셀 하나에 무늬 칸이 여럿 들어갑니다. 한가운데 점이 흰 칸에 떨어지면 픽셀이 흽니다. 검은 칸에 떨어지면 검습니다. 카메라가 조금만 움직여도 점이 옮겨 가 색이 번쩍입니다.
바둑판 무늬처럼 물체 표면에 입히는 그림을 텍스처라고 합니다. 이 번쩍임은 멀티샘플링이 아니라 텍스처를 읽는 쪽에서 막습니다.
텍스처 필터링은 텍스처를 읽을 때 이웃 칸의 색을 섞어 줍니다. 밉맵은 텍스처를 미리 여러 크기로 줄여 둔 것입니다. 멀리 있는 바닥에는 작게 줄인 그림을 읽습니다. 그러면 픽셀 하나에 무늬 칸이 몰리지 않습니다.
셰이더가 만든 테두리도 못 다듬습니다. 나뭇잎을 사각형 하나에 그리고 잎 바깥을 투명하게 도려내면, 그 윤곽은 삼각형의 변이 아니라 프래그먼트 셰이더의 계산에서 나옵니다. 멀티샘플링은 삼각형의 변만 보므로 이런 윤곽에는 계단이 남습니다.
비슷한 기법과 고르는 기준
같은 계단 문제를 푸는 방법은 여럿입니다. 무엇을 여러 번 하느냐로 갈립니다. 다 그린 이미지에서 색이 급하게 바뀌는 곳을 찾아 흐리게 만드는 방식을 후처리 안티에일리어싱이라고 합니다.
| 방식 | 여러 번 하는 일 | 고치는 것 | 대가 |
|---|---|---|---|
| 슈퍼샘플링 | 덮임 검사와 색 계산 둘 다 | 테두리와 안쪽 무늬 전부 | 색 계산과 메모리가 샘플 수만큼 는다 |
| 멀티샘플링 | 덮임 검사와 깊이 검사만 | 삼각형 테두리 | 메모리가 샘플 수만큼 는다 |
| 후처리 안티에일리어싱 | 없음 · 다 그린 이미지를 한 번 훑는다 | 눈에 띄는 경계 전부 | 글자 같은 잔무늬까지 흐려질 수 있다 |
멀티샘플링은 색 계산을 아낍니다. 그러면서도 테두리를 도형 모양대로 다듬습니다. 톱니가 주로 삼각형 테두리에서 나고 메모리에 여유가 있다면 멀티샘플링이 알맞습니다.
반대로 한 장을 그릴 때 중간 이미지를 여러 장 만들어 두는 방식에서는 잘 안 고릅니다. 중간 이미지마다 샘플이 붙어 메모리가 크게 불어나기 때문입니다. 색 계산을 뒤로 미루려고 중간 이미지를 쌓는 디퍼드 셰이딩이 그런 방식입니다. 이때는 후처리 쪽을 고르는 일이 많습니다.
관련 항목
멀티샘플링을 이루는 구성 요소
샘플링 · 멀티샘플 커버리지 · 커버리지 마스크 · 샘플 패턴 · 커스텀 샘플 위치 · 리졸브 · 샘플 셰이딩 · 알파 투 커버리지
멀티샘플링이 다루는 화면 결함
에일리어싱 · 계단 현상 · 모아레 · 스페큘러 에일리어싱 · 나이퀴스트 정리
멀티샘플링과 같은 결함을 두고 겨루는 안티에일리어싱 기법
슈퍼샘플링 · 후처리 안티에일리어싱 · FXAA · SMAA · 시간적 안티에일리어싱 · 커버리지 샘플링 안티에일리어싱
멀티샘플링이 끼어드는 파이프라인 단계
래스터화 · 프래그먼트 · 프래그먼트 셰이더 · 깊이 테스트 · 스텐실 테스트 · 출력 병합기 · 그래픽스 파이프라인
멀티샘플 값을 담는 메모리
렌더 타깃 · 멀티샘플 텍스처 · 깊이 버퍼 · 스텐실 버퍼 · 색 버퍼 · 프레임버퍼
멀티샘플링이 먹는 GPU 자원
메모리 대역폭 · 필레이트 · 해상도 · 타일 기반 렌더링 · GPU
멀티샘플링과 궁합이 갈리는 렌더링 방식
디퍼드 셰이딩 · 포워드 렌더링 · G 버퍼 · 후처리
멀티샘플링이 속하는 상위 분류
안티에일리어싱 · 렌더링 · 실시간 렌더링 · 그래픽스
멀티샘플링을 켜고 다루는 그래픽 API
다른 이름: multisampling · MSAA · multisample anti-aliasing · 멀티샘플 안티에일리어싱