Direct3D로 빌드된 UWP(유니버설 Windows 플랫폼) 앱에서 다중 샘플링을 사용하는 방법을 알아봅니다. 다중 샘플 앤티앨리어싱이라고도 하는 다중 샘플링은 별칭 가장자리의 모양을 줄이는 데 사용되는 그래픽 기술입니다. 실제 최종 렌더링 대상보다 더 많은 픽셀을 먼저 드로잉한 후, 값을 평균화하여 특정 픽셀에서 "부분" 가장자리의 모양을 유지시키기 위해 작동합니다. Direct3D에서 멀티샘플링이 실제로 작동하는 방식에 대한 자세한 설명 은 다중 샘플 앤티앨리어싱 래스터화 규칙을 참조하세요.
다중 샘플링 및 플립 모델 스왑체인
DirectX를 사용하는 UWP 앱은 플립 모델 스왑 체인을 사용해야 합니다. 플립 모델 스왑 체인은 멀티샘플링을 직접 지원하지 않지만, 장면을 멀티샘플링된 렌더링 대상 보기로 렌더링한 다음, 이를 백 버퍼로 해결한 후 제시하는 방식으로 멀티샘플링을 다른 방법으로 적용할 수 있습니다. 이 문서에서는 UWP 앱에 다중 샘플링을 추가하는 데 필요한 단계를 설명합니다.
다중 샘플링을 사용하는 방법
Direct3D 기능 수준은 특정 최소 샘플 개수 기능에 대한 지원을 보장하고 다중 샘플링을 지원하는 특정 버퍼 형식을 사용할 수 있도록 보장합니다. 그래픽 디바이스는 필요한 최소 개수보다 더 광범위한 형식 및 샘플 수를 지원하는 경우가 많습니다. 특정 DXGI 형식의 다중 샘플링에 대한 기능 지원을 확인한 다음 지원되는 각 형식에 사용할 수 있는 샘플 수를 확인하여 런타임에 다중 샘플링 지원을 확인할 수 있습니다.
ID3D11Device::CheckFeatureSupport 호출하여 다중 샘플링과 함께 사용할 수 있는 DXGI 형식을 확인합니다. 게임에서 사용할 수 있는 렌더링 대상 형식을 제공합니다. 렌더링 대상과 멀티샘플 해상 대상은 모두 동일한 형식을 사용해야 하므로 D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET 및 D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE를 모두 확인합니다.
**기능 수준 9: ** 기능 수준 9 디바이스 는 다중 샘플링된 렌더 타겟 형식에 대한 지원을 보장하지만, 다중 샘플링 확인 타겟에 대한 지원은 보장되지 않습니다. 따라서 이 항목에 설명된 다중 샘플링 기술을 사용하기 전에 이 검사가 필요합니다.
다음 코드는 모든 DXGI_FORMAT 값에 대한 다중 샘플링 지원을 확인합니다.
// Determine the format support for multisampling. for (UINT i = 1; i < DXGI_FORMAT_MAX; i++) { DXGI_FORMAT inFormat = safe_cast<DXGI_FORMAT>(i); UINT formatSupport = 0; HRESULT hr = m_d3dDevice->CheckFormatSupport(inFormat, &formatSupport); if ((formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE) && (formatSupport & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET) ) { m_supportInfo->SetFormatSupport(i, true); } else { m_supportInfo->SetFormatSupport(i, false); } }지원되는 각 형식에 대해 ID3D11Device::CheckMultisampleQualityLevels를 호출하여 샘플 수 지원을 쿼리합니다.
다음 코드는 지원되는 DXGI 형식에 대한 샘플 크기 지원을 확인합니다.
// Find available sample sizes for each supported format. for (unsigned int i = 0; i < DXGI_FORMAT_MAX; i++) { for (unsigned int j = 1; j < MAX_SAMPLES_CHECK; j++) { UINT numQualityFlags; HRESULT test = m_d3dDevice->CheckMultisampleQualityLevels( (DXGI_FORMAT) i, j, &numQualityFlags ); if (SUCCEEDED(test) && (numQualityFlags > 0)) { m_supportInfo->SetSampleSize(i, j, 1); m_supportInfo->SetQualityFlagsAt(i, j, numQualityFlags); } } }참고 타일식 리소스 버퍼에 대한 다중 샘플 지원을 확인해야 하는 경우 대신 ID3D11Device2::CheckMultisampleQualityLevels1 사용합니다.
원하는 샘플 수를 사용하여 버퍼를 만들고 대상 뷰를 렌더링합니다. 스왑 체인과 동일한 DXGI_FORMAT, 너비 및 높이를 사용하지만 1보다 큰 샘플 수를 지정하고 다중 샘플링된 텍스처 차원(예: D3D11_RTV_DIMENSION_TEXTURE2DMS )을 사용합니다. 필요한 경우 다중 샘플링에 가장 적합한 새 설정을 사용하여 스왑 체인을 다시 만들 수 있습니다.
다음 코드는 다중 샘플링된 렌더링 대상을 만듭니다.
float widthMulti = m_d3dRenderTargetSize.Width; float heightMulti = m_d3dRenderTargetSize.Height; D3D11_TEXTURE2D_DESC offScreenSurfaceDesc; ZeroMemory(&offScreenSurfaceDesc, sizeof(D3D11_TEXTURE2D_DESC)); offScreenSurfaceDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; offScreenSurfaceDesc.Width = static_cast<UINT>(widthMulti); offScreenSurfaceDesc.Height = static_cast<UINT>(heightMulti); offScreenSurfaceDesc.BindFlags = D3D11_BIND_RENDER_TARGET; offScreenSurfaceDesc.MipLevels = 1; offScreenSurfaceDesc.ArraySize = 1; offScreenSurfaceDesc.SampleDesc.Count = m_sampleSize; offScreenSurfaceDesc.SampleDesc.Quality = m_qualityFlags; // Create a surface that's multisampled. DX::ThrowIfFailed( m_d3dDevice->CreateTexture2D( &offScreenSurfaceDesc, nullptr, &m_offScreenSurface) ); // Create a render target view. CD3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc(D3D11_RTV_DIMENSION_TEXTURE2DMS); DX::ThrowIfFailed( m_d3dDevice->CreateRenderTargetView( m_offScreenSurface.Get(), &renderTargetViewDesc, &m_d3dRenderTargetView ) );깊이 버퍼는 다중 샘플링된 렌더링 대상과 일치하도록 너비, 높이, 샘플 수 및 텍스처 차원이 동일해야 합니다.
다음 코드는 다중 샘플링된 깊이 버퍼를 만듭니다.
// Create a depth stencil view for use with 3D rendering if needed. CD3D11_TEXTURE2D_DESC depthStencilDesc( DXGI_FORMAT_D24_UNORM_S8_UINT, static_cast<UINT>(widthMulti), static_cast<UINT>(heightMulti), 1, // This depth stencil view has only one texture. 1, // Use a single mipmap level. D3D11_BIND_DEPTH_STENCIL, D3D11_USAGE_DEFAULT, 0, m_sampleSize, m_qualityFlags ); ComPtr<ID3D11Texture2D> depthStencil; DX::ThrowIfFailed( m_d3dDevice->CreateTexture2D( &depthStencilDesc, nullptr, &depthStencil ) ); CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2DMS); DX::ThrowIfFailed( m_d3dDevice->CreateDepthStencilView( depthStencil.Get(), &depthStencilViewDesc, &m_d3dDepthStencilView ) );뷰포트 너비와 높이도 렌더링 대상과 일치해야 하므로 뷰포트를 만드는 것이 좋습니다.
다음 코드는 뷰포트를 만듭니다.
// Set the 3D rendering viewport to target the entire window. m_screenViewport = CD3D11_VIEWPORT( 0.0f, 0.0f, widthMulti / m_scalingFactor, heightMulti / m_scalingFactor ); m_d3dContext->RSSetViewports(1, &m_screenViewport);모든 프레임을 다중 샘플링 렌더 타깃으로 렌더링합니다. 렌더링이 완료되면 프레임을 표시하기 전에 ID3D11DeviceContext::ResolveSubresource 를 호출합니다. 이렇게 하면 Direct3D에서 다중 샘플링 작업을 수행하고 표시할 각 픽셀의 값을 계산하고 결과를 백 버퍼에 배치하도록 지시합니다. 그런 다음 백 버퍼는 앤티앨리어싱 처리된 최종 이미지를 포함하고 이를 표시할 수 있습니다.
다음 코드는 프레임을 표시하기 전에 하위 리소스를 확인합니다.
if (m_sampleSize > 1) { unsigned int sub = D3D11CalcSubresource(0, 0, 1); m_d3dContext->ResolveSubresource( m_backBuffer.Get(), sub, m_offScreenSurface.Get(), sub, DXGI_FORMAT_B8G8R8A8_UNORM ); } // The first argument instructs DXGI to block until VSync, putting the application // to sleep until the next VSync. This ensures that we don't waste any cycles rendering // frames that will never be displayed to the screen. hr = m_swapChain->Present(1, 0);