1.17 멀티 샘플 앤티앨리어싱(MSAA)

우리는 샘플링을 통해 세상을 인지합니다. 예를 들어, 우리의 눈은 30~60Hz 사이의 프레임 속도로 샘플링합니다. 샘플링 속도가 불충분하면 불쾌한 아티팩트가 발생할 수 있습니다. 컴퓨터 그래픽에서는 샘플링 제한을 관리하는 것이 끊임없는 도전입니다.

플레이그라운드 실행 - 1_17_msaa

일반적인 문제는 특히 래스터화 과정에서 이미지 해상도와 관련이 있습니다. 이전에 이 과정을 벽돌(픽셀)을 놓아 삼각형 영역을 덮는 것에 비유했습니다. 삼각형 가장자리를 확대하면 상황은 다음과 같이 설명할 수 있습니다:

래스터화 과정의 클로즈업
래스터화 과정의 클로즈업

래스터화 중에는 픽셀이 삼각형 내부에 있는지 외부에 있는지 판단하기 위한 휴리스틱이 필요합니다. 간단한 접근 방식은 픽셀의 중심을 확인하는 것입니다. 위 예시에서는 오직 하나의 픽셀 중심만이 삼각형 내부에 완전히 있습니다. 가장자리를 가로지르는 두 픽셀의 경우, 삼각형과 넓은 영역이 겹쳐도 중심이 외부에 있으므로 완전히 외부에 있는 것으로 간주됩니다. 이러한 픽셀에 대한 더 합리적인 색상 지정 전략은 겹치는 비율에 따라 삼각형의 색상과 배경 색상을 혼합하는 것일 수 있습니다.

이러한 종류의 아티팩트는 앨리어싱이라고 불리며, 낮은 출력 해상도에서 더 두드러집니다. 불충분한 샘플링 속도는 다른 이상한 아티팩트를 유발할 수도 있습니다. 예를 들어, 우리 예시에서 픽셀은 정사각형으로 모델링되지만, 색상은 오로지 그 중심에 의해 결정됩니다. 만약 픽셀보다 작은 구조가 있다면, 전체 픽셀은 그 작은 구조에서 중심점이 샘플링하는 것에 따라 색이 지정될 것입니다. 더 합리적인 접근 방식은 작은 구조의 색상을 평균화하는 것입니다.

다행히도, 물리적으로 모니터를 업그레이드하지 않고도 샘플링 품질을 향상시키는 방법이 있습니다. 우리는 이 문제를 해결하기 위해 앤티앨리어싱이라고 통칭되는 일련의 알고리즘을 사용합니다. 예를 들어, 앤티앨리어싱은 각 글리프가 매우 작고 해상도가 제한적일 때에도 텍스트 렌더링 품질을 향상시키기 위해 일반적으로 적용됩니다.

이 튜토리얼에서는 멀티 샘플 앤티앨리어싱(MSAA)으로 알려진 기본 앤티앨리어싱 방법을 소개하겠습니다. MSAA의 개념은 간단합니다: 먼저 각 픽셀에 대해 네 개의 샘플로 결과를 렌더링합니다. 그런 다음, 이 네 개의 샘플을 픽셀당 평균화하여 이미지를 원하는 크기로 축소합니다. 이 평균화는 배경과 삼각형의 겹치는 영역을 기반으로 혼합된 색상을 만드는 우리의 전략을 구현합니다. 실제 겹침 비율을 계산하는 비용이 많이 드는 작업을 더 많은 샘플을 단순히 검사하는 것으로 피할 수 있습니다.

MSAA는 WebGPU API의 내장 기능이므로, 몇 가지 추가 구성만으로 구현이 간단합니다. 이를 달성하는 방법을 살펴보겠습니다.

먼저, 멀티 샘플 텍스처를 생성합니다:

const msaaTexture = device.createTexture({
    size: [canvas.width, canvas.height],
    sampleCount: 4,
    format: navigator.gpu.getPreferredCanvasFormat(),
    usage: GPUTextureUsage.RENDER_ATTACHMENT,
});

또한 멀티 샘플링을 지원하도록 깊이 텍스처를 업데이트해야 합니다:

const depthTextureDesc = {
    size: [canvas.width, canvas.height, 1],
    sampleCount: 4,
    dimension: '2d',
    format: 'depth24plus-stencil8',
    usage: GPUTextureUsage.RENDER_ATTACHMENT
};

두 경우 모두, `sampleCount` 속성을 4로 설정하여 픽셀당 네 개의 샘플을 원함을 나타냅니다. `format` 및 `usage` 속성은 MSAA가 아닌 구성과 동일하게 유지됩니다.

MSAA는 셰이더에 투명하게 작동하므로 셰이더를 수정할 필요가 없다는 점은 주목할 가치가 있습니다. 주요 변경 사항은 렌더링 대상을 정의할 때 발생합니다.

다음으로, 색상 첨부 파일 구성을 업데이트합니다:

let colorAttachment = {
    view: view,
    resolveTarget: colorTextureView,
    clearValue: { r: 1, g: 0, b: 0, a: 1 },
    loadOp: 'clear',
    storeOp: 'store'
};

이 구성에서 두 가지 렌더링 대상을 지정합니다:

  1. `view` 속성은 이제 멀티 샘플 텍스처(`msaaTexture.createView()`)를 가리킵니다.

  2. 새로운 `resolveTarget` 속성을 도입했으며, 이는 실제 캔버스 텍스처 뷰(`colorTextureView`)를 가리킵니다. 최종, 해상된 출력이 여기에 저장됩니다.

렌더링 프로세스는 이제 두 단계로 진행됩니다:

  1. 장면은 먼저 멀티 샘플 텍스처(`msaaTexture`)에 렌더링됩니다.

  2. 결과는 자동으로 해상(평균화)되어 `resolveTarget`으로 출력됩니다.

이 두 단계 프로세스는 우리가 수행한 구성 변경 외에 추가 코드 없이 투명하게 진행됩니다.

MSAA 적용 전(왼쪽)과 후(오른쪽)의 품질 향상은 매우 두드러집니다.
MSAA 적용 전(왼쪽)과 후(오른쪽)의 품질 향상은 매우 두드러집니다.

MSAA의 효과를 설명하기 위해, MSAA를 활성화하기 전과 후의 렌더링된 장면을 확대하여 비교할 수 있습니다. MSAA가 활성화된 버전에서는 가장자리가 더 부드러워지고 앨리어싱 아티팩트가 줄어들어 그 차이가 눈에 띄게 나타날 것입니다.

GitHub에 의견 남기기