기록공간

[DirectX 12] 기본지식 - 다중 샘플링(Multisampling) 본문

DirectX/기초

[DirectX 12] 기본지식 - 다중 샘플링(Multisampling)

입코딩 2020. 2. 5. 10:41
반응형

모니터의 픽셀들이 무한히 작지는 않기 때문에, 모니터 화면에 선을 완벽하게 나타내는 것은 불가능하다. 모니터에 선을 출력했을때 흔히 나타나는 현상이 있는데 이것을 '계단 현상' 또는 앨리어싱(Aliasing) 효과라고 부른다. 삼각형 변에서도 이와 비슷한 효과가 나타난다.

 

모니터의 해상도를 키운다면 이런 현상이 줄어들긴 하겠지만 완벽하게 없애기란 불가능하다. 그래서 이를 해결하기 위한 여러 기법이 있다. 이를 보통은 계단 현상을 제고 한다고 하여 '안티 앨리어싱(Antialiasing)' 이라고 부른다. 한번 알아 보도록 하겠다.

 

계단 현상(위)과 안티 엘리어싱을 적용한 경우(아래)

우선 첫번째 기법은 슈퍼샘플링(초과표본화)(Supersampling)이라는 기법이다. 우선 그릴 후면 버퍼를 화면 해상도의 4배 (가로, 세로로 2배씩)로 잡고, 장면을 후면 버퍼에 렌더링한다. 그리고 환원 공정을 거쳐 후면 버퍼의 원래 크기로 되돌려 화면에 출력된다.

 

이 환원 공정은 다운샘플링(Downsampling)라고도 불리는데, 4배로 키운 후면 버퍼(와 깊이 버퍼)에서 근처 4픽셀 블록의 네 색상의 평균을 그 블록에 해당하는 픽셀의 최종 색상으로 사용한다. 본질적으로, 슈퍼샘플링은 화면 해상도를 소프트웨어에서 증가하는 것이라 할 수 있다.

 

하지만 슈퍼샘플링은 4배로 늘린 후면 버퍼의 모든 서브 픽셀들을 계산하기 때문에 픽셀 처리량과 메모리 소비량이 4배라서 비용이 높다. 그래서 Direct3D에서는 두번째 기법인 멀티샘플링(다중표본화)(Multisampling)이라는 절충적인 기법을 지원한다. 멀티샘플링은 일부 계산 결과를 부분픽셀(Subpixel)들 사이에서 공유하기 때문에 슈퍼샘플링보다 비용이 낮다.

 

멀티샘플링도 슈퍼샘플링처럼 크기가 화면 해상도의 4배인 후면 버퍼와 깊이 버퍼를 사용한다. 그러나 멀티샘플링은 이미지 색상을 각 부분픽셀마다 계산하는 것이 아니라 픽셀당 한 번만 계산하고(4개의 픽셀을 하나의 픽셀로 치고 평균 색상을 구한다), 그 색상과 서브 픽셀들의 가시성(각 서브 픽셀이 보이는가?)(부분 픽셀당 깊이 스텐실 판정이 일어남)과 포괄도(각 서브 픽셀의 중심이 다각형의 내부에 존재하는가?)(부분픽셀을 다각형이 어느 정도나 덮고 있는지)를 이용하여 최종 색상을 결정한다.

 

슈퍼샘플링과 멀티샘플링의 픽셀 계산법의 차이점을 보여준다. 슈퍼샘플링이 멀티샘플링에 비해 각 서브 픽셀 색상을 모두 계산하기 때문에 좀 더 정확한 픽셀을 표현할 수 있다.
삼각형을 제한된 픽셀의 출력하려 했을때 다중 샘플링을 사용하여 어떻게 필터링해서 최종적으로 렌더링 되는지를 보여준다

서브 픽셀들이 배치되는 지점 패턴은 하드웨어 제조사마다 다를 수 있다. Direct3D 자체에는 부분픽셀의 배치 방식이 구체적으로 정의되어 있지 않다. 분할 패턴들마다 각자 장단점을 가지고 있다.


Direct3D의 멀티샘플링

Direct3D에서는 모든 DXGI형식에 대한 4X 멀티샘플링을 지원한다. 왜냐하면 멀티샘플링은 시간이 많이 걸리는 연산이기 때문에 하드웨어적으로 처리해야하기 때문이다.

 

우선 멀티샘플링을 위해서는 DXGI_SAMPLE_DESC라는 구조체를 적절히 채워야 한다.

 

D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT는 한 픽셀에서 추출할 수 있는 최대 표본 개수를 뜻한다. 최대 32개까지 가능하다.

표본의 개수(Count)가 많을수록, 그리고 품질 수준(Quality)이 높을수록 렌더링 비용도 증가하므로, 프로그래머는 비용과 속도 사이의 절충선을 잘 잡아야 한다. 품질 수준의 범위는 텍스처 형식과 표본 개수에 의존한다. 

 

주어진 텍스처 형식과 표본 개수의 조합에 대한 품질 수준들의 개수는 CheckFeatureSupport()라는 메서드로 알아낼 수 있다.

사용하는 예를 코드로 알아보자.

// CheckFeatureSupport의 두번째 인자에 들어갈 구조체
// (Direct3D에서 이미 정의되어 있음)
typedef struct D3D12_FEATURE_DATA_MULTISAMPLING_QUALITY_LEVELS
{
    DXGI_FORMAT Format;
    UINT        SampleCount;
    D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG  Flags;
    UINT        NumQualityLevels;
} D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS;

// 사용법
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS d3dQualityLevels;
// 텍스처 형식을 지정한다.
d3dQualityLevels.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
// 표본화 갯수를 지정한다.
d3dQualityLevels.SampleCount = 4;
// 추가 기능을 지정한다. (대부분은 NONE)
d3dQualityLevels.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE
// 값을 0으로 초기화 한다.
d3dQualityLevels.NumQualityLevels = 0;
// CheckFeatureSupport 메서드를 사용하여 품질 수준들을 받아온다.
pd3dDevice->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
&d3dQualityLevels, sizeof(D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS));

NumQualityLevels를 0으로 초기화만 하는 이유는 CheckFeatureSupport 메서드를 통해 형식에 맞는 품질 수준의 개수를 NumQualityLevels에 설정하기 때문이다. 유효한 품질 수준들은 0에서 NumQualityLevels - 1까지이다.

 

표본 개수는 앞에서 봤듯이 최대 32개까지 지원하고 있지만 보통 실제 응용에서는 성능 및 메모리 비용을 합리적인 수준으로 유지하기 위해 4개나 8개만 사용하는 경우가 많다.

 

멀티샘플링을 사용하고 싶지 않으면 표본 개수를 1로, 품질 수준을 0으로 설정하면 된다.

반응형
Comments