멀티샘플 커버리지
고친 사람 github-actions[bot]
멀티샘플 커버리지는 도형 하나가 픽셀 안의 어느 검사 지점을 덮었는지 알려 줍니다. 그래픽 카드는 이 표시를 보고 도형의 색을 어느 지점에 적을지 정합니다. 덮인 지점이 많을수록 그 픽셀은 도형 색에 가까워집니다. 그래서 도형 테두리의 톱니가 부드럽게 풀립니다.
쉽고 빠른 이해
멀티샘플 커버리지는 도형이 픽셀의 어디를 덮었는지 남기는 체크 표시입니다. 픽셀 안에 점을 넷 찍어 두고 비스듬한 변이 그중 셋을 가렸다면, 그 셋에 표시가 붙습니다.
이 표시가 없으면 픽셀은 칠하거나 안 칠하거나 둘 중 하나뿐입니다. 그래서 테두리에 계단이 생깁니다. 덮인 몫을 알아야 테두리 픽셀을 중간 색으로 칠할 수 있습니다.
- 도형이 들어오면 점마다 도형 안인지 검사해 표시를 만듭니다
- 색은 픽셀마다 한 번만 계산해서 표시가 붙은 점에만 적습니다
- 다 그린 뒤 점들의 색을 평균 내 픽셀 색 하나로 줄입니다
대가는 메모리입니다. 점마다 색을 따로 담으니 점이 넷이면 칸도 넷입니다. 또 이 표시는 도형의 테두리만 알아봅니다. 도형 안쪽에 그려 넣은 무늬의 톱니는 못 고칩니다.
상세
이 절은 멀티샘플 커버리지가 무엇을 기록하는지, 왜 덮인 개수가 아니라 덮인 위치를 남기는지 다룹니다. 비스듬한 변이 걸친 픽셀 하나와, 변 하나를 나눠 가진 삼각형 둘을 가지고 봅니다.
출석부처럼 남기는 덮임 표시
학교 출석부를 떠올리면 쉽습니다. 학생 넷의 이름 옆에 온 사람만 동그라미를 칩니다. 몇 명이 왔는지와 함께 누가 왔는지도 남습니다.
화면은 작은 칸이 격자로 늘어선 것입니다. 그 칸 하나가 픽셀입니다. 화면에 그리는 도형은 대개 삼각형 여러 개로 쪼개져 들어옵니다.
삼각형이 어느 픽셀을 덮는지 골라내는 절차를 래스터화라고 합니다. 기본 래스터화는 픽셀 한가운데 점 하나만 보고 정합니다. 그 점이 삼각형 안이면 픽셀을 칠합니다. 밖이면 건너뜁니다.
모양을 알아보려고 이렇게 찍어 보는 점이 샘플입니다. 샘플이 하나뿐이면 픽셀은 전부 칠해지거나 전부 빠집니다.
그래서 비스듬한 변을 따라 칸이 들쭉날쭉하게 칠해집니다. 이 톱니를 계단 현상이라고 합니다.
톱니를 누그러뜨리는 기법들을 묶어 안티에일리어싱이라고 부릅니다. 테두리 픽셀을 중간 색으로 칠해 계단이 덜 보이게 하는 기법들입니다.
멀티샘플링은 그런 기법 가운데 하나입니다. 픽셀 하나에 샘플을 여럿 둬서 톱니를 줄입니다. 흔히 MSAA(Multisample Anti-Aliasing, 멀티샘플 안티에일리어싱)라고 줄여 부릅니다.
멀티샘플 커버리지는 멀티샘플링에서 도형 하나가 픽셀 하나의 어느 샘플을 덮었는지 적은 표시입니다. 출석부의 동그라미가 이것입니다. 줄여서 커버리지라고도 부릅니다.
코드를 얼마나 시험했는지 재는 테스트 커버리지와는 이름만 같습니다. 여기서 커버리지는 도형이 화면을 덮는다는 뜻의 덮임입니다.
샘플마다 비트 하나
샘플 하나의 상태는 덮였다와 안 덮였다 둘뿐입니다. 그래서 샘플마다 비트 하나면 됩니다. 샘플이 넷이면 커버리지는 네 비트짜리 비트 마스크가 됩니다. 이 마스크를 커버리지 마스크라고 부릅니다.
아래는 샘플 넷 중 0번·1번·2번이 덮인 픽셀입니다. 맨 오른쪽 비트가 0번 샘플입니다.
int coverage = 0b0111; // 0·1·2번 덮임
int n = popcount(coverage); // 3
float share = n / 4.0f; // 0.75
popcount 는 켜진 비트 수를 세는 함수입니다. 덮인 샘플 수를 전체 샘플 수로 나누면 도형이 픽셀을 덮은 몫이 나옵니다. 이 픽셀은 4분의 3이 덮였습니다.
색은 한 번, 적는 곳은 덮인 샘플만
멀티샘플링은 픽셀 하나에 색을 담는 칸을 샘플 수만큼 따로 둡니다. 샘플이 넷이면 색 칸도 넷입니다. 카메라에서 떨어진 거리를 담는 칸도 샘플마다 하나씩 있습니다.
색을 계산하는 작은 프로그램을 프래그먼트 셰이더라고 합니다. 멀티샘플링은 이 프로그램을 픽셀마다 한 번만 돌립니다. 샘플마다 돌리면 계산이 샘플 수만큼 불어나기 때문입니다.
계산한 색 하나는 커버리지 비트가 켜진 샘플에만 적힙니다. 꺼진 샘플에는 앞서 그려 둔 색이 남습니다. 파란 배경 위에 빨간 삼각형을 그렸다면 위 픽셀의 샘플 셋은 빨강, 하나는 파랑입니다.
덮인 샘플이 하나도 없으면 셰이더는 그 픽셀에서 아예 돌지 않습니다. 하나라도 덮였으면 한 번 돕니다.
다 그린 뒤에는 샘플들의 색을 평균 내 픽셀 색 하나로 줄입니다. 이 단계를 리졸브라고 합니다. 빨강 셋과 파랑 하나가 섞여 빨강에 가까운 보랏빛이 나옵니다. 커버리지의 몫 4분의 3이 색의 비율 4분의 3이 된 셈입니다.
개수가 아니라 위치를 남기는 이유
몫만 필요하다면 4분의 3이라는 숫자 하나로 충분해 보입니다. 그 숫자를 불투명도로 삼아 기존 색과 섞으면 되기 때문입니다.
색에 붙는 불투명도 값을 알파라고 합니다. 1 이면 뒤가 안 비치고 0 이면 다 비칩니다. 알파를 비율로 삼아 새 색과 기존 색을 섞는 방식이 알파 블렌딩입니다.
걸리는 것은 변 하나를 나눠 가진 삼각형 둘입니다. 빨간 삼각형 둘이 픽셀 한가운데를 지나는 변을 함께 씁니다. 두 삼각형이 각자 픽셀의 절반을 덮는다고 합시다. 파란 배경 위라면 이 픽셀은 온전히 빨강이어야 합니다.
아래 표는 두 방식이 이 픽셀을 어떻게 칠하는지 견줍니다.
| 단계 | 몫으로 섞을 때 | 커버리지로 적을 때 |
|---|---|---|
| 배경 | 파랑뿐 | 샘플 넷 모두 파랑 |
| 첫째 삼각형 | 빨강 절반 · 파랑 절반 | 샘플 0·1 빨강 |
| 둘째 삼각형 | 빨강 4분의 3 · 파랑 4분의 1 | 샘플 2·3 빨강 |
| 리졸브 뒤 | 파랑이 비친다 | 빨강뿐 |
몫으로 섞으면 둘째 삼각형의 빨강 절반이 픽셀 전체에 고르게 섞입니다. 숫자 하나에는 어느 절반을 덮었는지가 안 들어 있기 때문입니다. 그래서 파랑이 4분의 1 남습니다. 변을 따라 배경색이 실금처럼 비칩니다.
커버리지는 어느 샘플인지를 압니다. 첫째 삼각형이 0번·1번을, 둘째가 2번·3번을 칠하니 겹치지도 빠지지도 않습니다. 변 위에 딱 걸린 샘플은 두 삼각형 중 한쪽에만 들어가도록 래스터화 규칙이 정해 둡니다. 흔히 탑-레프트 규칙이라고 부릅니다.
거리도 같은 까닭으로 샘플마다 따집니다. 카메라에 가까운 도형이 보이도록 거리를 견주는 검사가 깊이 테스트입니다. 두 도형이 한 픽셀 안에서 엇갈리면 샘플마다 앞에 선 도형이 다를 수 있습니다. 위치를 알아야 샘플마다 이긴 쪽 색을 남길 수 있습니다.
적기 전에 줄어드는 커버리지
래스터화가 만든 커버리지가 끝까지 가지는 않습니다. 색을 적기 전에 몇 단계가 비트를 끕니다. 단계마다 비트를 끄기만 합니다. 켜는 단계는 없습니다. 이 소절은 그 단계들을 짚습니다. 비트 넷이 어떻게 줄어드는지도 봅니다.
첫째는 샘플 마스크입니다. 앱이 미리 정해 두는 비트 마스크입니다. 커버리지와 비트 단위 AND 로 겹쳐서 둘 다 켜진 비트만 남깁니다. 꺼 둔 샘플에는 어떤 도형도 색을 적지 못합니다.
샘플 마스크는 도형을 샘플 일부에만 그리고 싶을 때 씁니다. 넷 중 둘에만 그리면 리졸브 때 도형 색이 절반만 섞입니다. 그러면 도형이 반쯤 비쳐 보입니다.
둘째는 알파 투 커버리지입니다. 이 기능은 셰이더가 내놓은 알파를 켜진 비트 수로 바꿉니다. 알파가 0.5 면 넷 중 둘만 남기는 식입니다.
셋째는 깊이 테스트와 스텐실 테스트입니다. 스텐실 테스트는 화면에 미리 그려 둔 표시를 보고 그릴 곳을 가리는 검사입니다. 둘 다 샘플마다 돕니다. 검사에서 떨어진 샘플은 비트가 꺼집니다.
아래 그림은 0번·1번·2번이 덮인 픽셀이 두 단계를 지나는 모습입니다.
flowchart TD
A["래스터화가 만든 커버리지 · 0111"] --> B["샘플 마스크 1101 과 AND · 0101"]
B --> C["깊이 테스트 · 2번 샘플은 앞서 그린 도형보다 멀어서 떨어진다 · 0001"]
C --> D["남은 0번 샘플에만 색을 적는다"]
처음에 덮인 샘플은 셋입니다. 색을 받는 샘플은 하나뿐입니다. 리졸브 때 이 도형이 픽셀에서 차지하는 몫은 4분의 1이 됩니다.
한가운데가 밖인 테두리 픽셀
커버리지가 켜졌다고 픽셀 한가운데가 도형 안이라는 보장은 없습니다. 변이 픽셀 구석만 스치면 구석 샘플 하나만 덮이고 한가운데는 밖에 남습니다.
셰이더는 보통 픽셀 한가운데를 기준점으로 삼아 돕니다. 그 픽셀의 색을 한 번 계산할 때 한가운데 위치를 쓴다는 뜻입니다.
물체 표면에 입히는 그림을 텍스처라고 합니다. 벽돌 사진을 사각형 하나에 붙여 벽을 그리는 식입니다.
삼각형 꼭짓점마다 텍스처의 어느 곳을 읽을지 적은 좌표가 붙어 있습니다. 셰이더는 꼭짓점 셋의 좌표를 기준점 위치에 맞춰 섞어서 받습니다. 이렇게 위치에 맞춰 섞는 일을 보간이라고 합니다.
기준점이 삼각형 밖이면 보간한 좌표도 삼각형 바깥으로 밀려납니다. 그러면 텍스처에서 이 삼각형에 붙인 그림의 바깥을 읽습니다. 한 텍스처에 여러 물체의 그림을 모아 두었다면 옆 그림의 색이 테두리에 묻어납니다.
기준점을 덮인 샘플 쪽으로 옮겨 이를 막는 방식이 센트로이드 샘플링입니다. 기준점이 덮인 영역 안에 들어오니 바깥 값이 나오지 않습니다.
커버리지가 못 다듬는 테두리
커버리지는 삼각형의 변만 압니다. 나뭇잎을 사각형 하나에 그리고 셰이더가 잎 바깥을 투명하게 버린다고 합시다. 사각형 안의 샘플은 모두 켜져 있습니다. 그래서 잎 윤곽은 커버리지에 안 잡히고 계단이 남습니다.
알파 투 커버리지가 이 틈을 메우는 데 쓰입니다. 잎 가장자리에서 알파가 줄어드는 만큼 켜진 비트도 줄어듭니다. 그러면 윤곽 픽셀도 중간 색을 얻습니다.
도형 안쪽 무늬도 못 고칩니다. 색 계산이 픽셀마다 한 번이라서 무늬가 픽셀보다 잘면 그중 한 점의 색만 뽑힙니다. 물체가 조금만 움직여도 뽑히는 점이 바뀌어 픽셀 색이 확 달라집니다. 그래서 무늬가 번쩍거립니다.
대책 하나는 셰이더를 샘플마다 돌리는 샘플 셰이딩입니다. 계산은 샘플 수만큼 늘어납니다. 대신 샘플마다 색을 따로 구합니다.
다른 대책은 텍스처를 읽는 쪽에서 무늬를 미리 뭉개는 것입니다. 작게 보이는 텍스처는 미리 줄여 둔 판을 읽습니다. 줄인 판은 잔 무늬의 색이 이미 평균 나 있어 번쩍이지 않습니다. 이 판을 밉맵이라고 합니다.
몫을 나타내는 단계에도 끝이 있습니다. 샘플이 넷이면 몫은 0 · 4분의 1 · 절반 · 4분의 3 · 전부 다섯 가지뿐입니다. 샘플을 늘리면 단계가 촘촘해집니다. 대신 샘플마다 색과 거리를 담는 메모리가 그만큼 늘어납니다.
관련 항목
멀티샘플 커버리지가 속하는 상위 분류
멀티샘플링 · 안티에일리어싱 · 래스터화 · 그래픽스 파이프라인 · 그래픽스
멀티샘플 커버리지를 이루는 구성 요소
커버리지 마스크 · 비트 마스크 · 샘플링 · 샘플 패턴 · 커스텀 샘플 위치
멀티샘플 커버리지의 비트를 끄는 검사
샘플 마스크 · 알파 투 커버리지 · 깊이 테스트 · 스텐실 테스트 · 알파 테스트
멀티샘플 커버리지가 거치는 처리 단계
탑-레프트 규칙 · 프래그먼트 · 프래그먼트 셰이더 · 보간 · 센트로이드 샘플링 · 샘플 셰이딩 · 리졸브 · 출력 병합기
멀티샘플 커버리지가 가리키는 샘플을 담는 메모리
렌더 타깃 · 멀티샘플 텍스처 · 깊이 버퍼 · 스텐실 버퍼 · 프레임버퍼
멀티샘플 커버리지가 다루는 화면 결함
에일리어싱 · 계단 현상 · 컨플레이션 아티팩트
멀티샘플 커버리지와 같은 톱니를 두고 겨루는 기법
슈퍼샘플링 · 알파 블렌딩 · 해석적 안티에일리어싱 · 후처리 안티에일리어싱 · FXAA · SMAA · 시간적 안티에일리어싱 · 커버리지 샘플링 안티에일리어싱
멀티샘플 커버리지와 이름이 겹치는 이웃
다른 이름: multisample coverage · sample coverage · 샘플 커버리지 · MSAA 커버리지