Adreno GPU上从 OpenGL ES 迁移到 Direct3D11.1介绍 (4)
6.2.5 Framebuffer对象
在OpenGL ES中,渲染目标是使用Framebuffer对象(FBOs)创建的。FBOs有附着点用于颜色缓冲(如果使用多个渲染目标,则不止一个)和深度/模板缓冲(深度和模板可以分开或结合在一个交错缓冲中)。下面的代码块演示了创建一个FBO的颜色附件,可以用作纹理和深度/模板附件,可以作为纹理获取。
glGenTextures( 1, &m_hTexture );
glBindTexture( GL_TEXTURE_2D, m_hTexture );
glTexImage2D( GL_TEXTURE_2D, 0, nInternalFormat, nWidth, nHeight, 0, nFormat,
nType, NULL );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
m_hTexture, 0 );
glGenTextures( 1, &m_hDepthTexture);
glBindTexture( GL_TEXTURE_2D, m_hDepthTexture);
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, nWidth, nHeight, 0,
GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
m_hDepthTexture, 0);
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
m_hDepthTexture, 0);
为了在Direct3D11中创建一个可以作为纹理的渲染目标,我们需要创建一个带有着色器资源视图和渲染目标视图的纹理。下面的代码块演示了如何创建一个具有纹理颜色缓冲和深度/模板缓冲的渲染目标。
D3D11_TEXTURE2D_DESC textureDesc;
ZeroMemory( &textureDesc, sizeof(textureDesc) );
textureDesc.Width = nWidth;
textureDesc.Height = nHeight;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
textureDesc.SampleDesc.Count = 1;
textureDesc.Usage = D3D11_USAGE_DEFAULT;
textureDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
textureDesc.CPUAccessFlags = 0;
textureDesc.MiscFlags = 0;
// Render target view
D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
ZeroMemory(&renderTargetViewDesc, sizeof(renderTargetViewDesc));
renderTargetViewDesc.Format = textureDesc.Format;
renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
renderTargetViewDesc.Texture2D.MipSlice = 0;
// Shader resource view
D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
ZeroMemory(&shaderResourceViewDesc, sizeof(shaderResourceViewDesc));
shaderResourceViewDesc.Format = textureDesc.Format;
shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
shaderResourceViewDesc.Texture2D.MipLevels = 1;
shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
// Sampler description
D3D11_SAMPLER_DESC samplerDesc;
ZeroMemory(&samplerDesc, sizeof(samplerDesc));
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
samplerDesc.MaxAnisotropy = 0;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
samplerDesc.BorderColor[0] = 0.0f;
samplerDesc.BorderColor[1] = 0.0f;
samplerDesc.BorderColor[2] = 0.0f;
samplerDesc.BorderColor[3] = 0.0f;
// Create Texture
ComPtr<ID3D11Texture2D> pTexture;
if ( FAILED(pD3DDevice->CreateTexture2D( &textureDesc, NULL, &pTexture) ) )
{
return FALSE;
}
// Create Render Target View
ComPtr<ID3D11RenderTargetView> pTextureRenderTargetView;
if ( FAILED(pD3DDevice->CreateRenderTargetView( pTexture.Get(),
&renderTargetViewDesc,&pTextureRenderTargetView ) ) )
{
return FALSE;
}
// Create Shader Resource View
ComPtr<ID3D11ShaderResourceView> pTextureShaderResourceView;
if ( FAILED(pD3DDevice->CreateShaderResourceView( pTexture.Get(),
&shaderResourceViewDesc,&pTextureShaderResourceView) ) )
{
return FALSE;
}
// Create Sampler State
ComPtr<ID3D11SamplerState> pTextureSampler;
if ( FAILED(pD3DDevice->CreateSamplerState( &samplerDesc, &pTextureSampler ) ) )
{
return FALSE;
}
// Create a depth/stencil texture for the depth attachment
ComPtr<ID3D11Texture2D> pDepthTexture;
textureDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
textureDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
if ( FAILED(pD3DDevice->CreateTexture2D( &textureDesc, NULL, &pDepthTexture )))
return FALSE;
ComPtr<ID3D11DepthStencilView> pDepthStencilView;
D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));
depthStencilViewDesc.Format = textureDesc.Format;
depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
depthStencilViewDesc.Texture2D.MipSlice = 0;
if ( FAILED(pD3DDevice ->CreateDepthStencilView( pDepthTexture.Get(), &depthStencilViewDesc, &pDepthStencilView ) ) )
return FALSE;
ID3D11ShaderResourceView可以用来将纹理绑定到像素着色器。要渲染到渲染目标,ID3D11RenderTargetView和ID3D11DepthStencilView使用如下:
ID3D11RenderTargetView* pRTViews[1] = { pTexture0RenderTargetView.Get() };
pD3DDeviceContext->OMSetRenderTargets( 1, pRTViews, pDepthStencilView.Get() );
深度纹理
渲染目标的一个常见用途是渲染到一个深度纹理的效果,如阴影映射。Adreno GPU支持深度纹理,该功能通过GL_OES_depth_texture在OpenGL ES 2.0中公开,是OpenGL ES 3.0核心功能的一部分。然而,微软选择在Direct3D11.1特性级别9_3中不公开深度纹理。因此,实现等效效果的最简单方法是渲染为单通道32位颜色纹理(DXGI_FORMAT_R32_FLOAT),并编写一个着色器来计算深度值并将其写入颜色缓冲区。为了获得精度的最佳使用,建议将值1.0 - (z/w)写入每个像素。下面的HLSL代码块将深度值写入一个插值器,并发送给像素着色器:
vso.Position = mul(MatModelViewProj, Position);
// Store depth for pixel shader
// Depth is Z/W.
// Use 1 - z/w to get better precision
vso.Depth = (1.0 - vso.Position.z / vso.Position.w);
DirectX Adreno SDK中的几个例子使用了这个功能,包括DepthOfField, ShadowMap和级联阴影地图的例子。有关如何模拟深度纹理的更多细节,请参阅这些示例的源代码。