Muestreo múltiple en aplicaciones de Plataforma universal de Windows (UWP)
Aprende a usar el muestreo múltiple en aplicaciones de Plataforma universal de Windows (UWP) creadas con Direct3D. El muestreo múltiple, también conocido como suavizado multimuestreo, es una técnica gráfica que se usa para reducir la apariencia de los bordes con alias. Funciona dibujando más píxeles de los que realmente están en el destino de representación final y, a continuación, promediando los valores para mantener la apariencia de un borde "parcial" en determinados píxeles. Para obtener una descripción detallada de cómo funciona realmente el muestreo múltiple en Direct3D, consulte Reglas de rasterización de suavizado multisample.
Muestreo múltiple y la cadena de intercambio del modelo de volteo
Las aplicaciones para UWP que usan DirectX deben usar cadenas de intercambio de modelos invertida. Las cadenas de intercambio de modelos invertidos no admiten el muestreo múltiple directamente, pero el muestreo múltiple todavía se puede aplicar de otra manera mediante la representación de la escena en una vista de destino de representación de muestreo múltiple y, a continuación, resolver el destino de representación multimuestreo al búfer atrás antes de presentarlo. En este artículo se explican los pasos necesarios para agregar el muestreo múltiple a la aplicación para UWP.
Cómo usar el muestreo múltiple
Los niveles de características de Direct3D garantizan la compatibilidad con funcionalidades específicas de recuento de muestras mínimas y garantizan que determinados formatos de búfer estarán disponibles que admiten el muestreo múltiple. Los dispositivos gráficos suelen admitir una gama más amplia de formatos y recuentos de muestras que el mínimo necesario. La compatibilidad con el muestreo múltiple se puede determinar en tiempo de ejecución comprobando la compatibilidad de características para el muestreo múltiple con formatos DXGI específicos y, a continuación, comprobando los recuentos de ejemplo que puede usar con cada formato admitido.
Llame a ID3D11Device::CheckFeatureSupport para averiguar qué formatos DXGI se pueden usar con el muestreo múltiple. Proporcione los formatos de destino de representación que puede usar el juego. Tanto el destino de representación como el destino de resolución deben usar el mismo formato, por lo que debe comprobar si hay D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET y D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE.
**Nivel de característica 9: ** Aunque los dispositivos de nivel de característica 9 garantizan la compatibilidad con formatos de destino de representación multimuestreo, no se garantiza la compatibilidad con los destinos de resolución de varios ejemplos. Por lo tanto, esta comprobación es necesaria antes de intentar usar la técnica de muestreo múltiple descrita en este tema.
El código siguiente comprueba la compatibilidad con el muestreo múltiple para todos los valores de 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); } }
Para cada formato admitido, consulte la compatibilidad con el recuento de muestras llamando a ID3D11Device::CheckMultisampleQualityLevels.
El código siguiente comprueba la compatibilidad con el tamaño de ejemplo para los formatos DXGI admitidos:
// 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); } } }
Nota Use ID3D11Device2::CheckMultisampleQualityLevels1 en su lugar si necesita comprobar la compatibilidad con variosmples para los búferes de recursos en mosaico.
Cree un búfer y represente la vista de destino con el recuento de muestras deseado. Use la misma DXGI_FORMAT, ancho y alto que la cadena de intercambio, pero especifique un recuento de muestras mayor que 1 y use una dimensión de textura multimuestreo (D3D11_RTV_DIMENSION_TEXTURE2DMS por ejemplo). Si es necesario, puede volver a crear la cadena de intercambio con nuevas configuraciones que sean óptimas para el muestreo múltiple.
El código siguiente crea un destino de representación multimuestreo:
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 ) );
El búfer de profundidad debe tener el mismo ancho, alto, recuento de muestras y dimensión de textura para que coincida con el destino de representación de muestreo múltiple.
El código siguiente crea un búfer de profundidad de muestreo múltiple:
// 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 ) );
Ahora es un buen momento para crear la ventanilla, ya que el ancho y el alto de la ventanilla también deben coincidir con el destino de representación.
El código siguiente crea una ventanilla:
// 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);
Representar cada fotograma en el destino de representación multimuestreo. Cuando se complete la representación, llame a ID3D11DeviceContext::ResolveSubresource antes de presentar el marco. Esto indica a Direct3D que peforme la operación de muestreo múltiple, calculando el valor de cada píxel para mostrar y colocando el resultado en el búfer de reserva. Después, el búfer de reserva contiene la imagen final con alias y se puede presentar.
El código siguiente resuelve el subrecurso antes de presentar el marco:
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);