2017-05-06 79 views
0

我一直在为游戏制作3D渲染器,直到现在,它先使用DrawIndexed渲染所有无纹理网格,然后渲染所有纹理网格。为了提高性能,我已经切换到了DrawIndexedInstanced,并且使纹理网格首先被渲染,并且这揭示了如何设置我的alpha混合和/或深度检查的问题。以下图片应该说明的问题是什么:Direct3D 11深度模板/ alpha混合问题

View through the top of the front-most textures (textured meshes rendered first)

The same view, slightly different angle (textureless meshes rendered first)

在前台和后台的纹理矩形网格行,并在前台的人有部分透明的网格。在中间行是透明度设置为0.3f的无纹理网格。当首先渲染纹理网格时,无纹理的网格会被前景中的透明网格遮挡。然而,当它是首先渲染的无纹理网格时,即使它们的透明度在0.3f时,它们也会完全遮住它们背后的网格化网格。这种情况发生在未经纹理化的网格掩盖了其他未经纹理化的网格时,alpha混合在该场景中正常工作。

这是我设置了光栅化状态,深度模具状态和深度模具图:

ID3D11Texture2D *pBackBuffer; 
D3D11_TEXTURE2D_DESC backBufferDesc; 
m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); 
pBackBuffer->GetDesc(&backBufferDesc); 
RELEASE_RESOURCE(pBackBuffer); 

// creating a buffer for the depth stencil 
D3D11_TEXTURE2D_DESC depthStencilBufferDesc; 
ZeroMemory(&depthStencilBufferDesc, sizeof(D3D11_TEXTURE2D_DESC)); 

depthStencilBufferDesc.ArraySize = 1; 
depthStencilBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; 
depthStencilBufferDesc.CPUAccessFlags = 0; // No CPU access required. 
depthStencilBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; 
depthStencilBufferDesc.Width = backBufferDesc.Width; 
depthStencilBufferDesc.Height = backBufferDesc.Height; 
depthStencilBufferDesc.MipLevels = 1; 
depthStencilBufferDesc.SampleDesc.Count = 4; 
depthStencilBufferDesc.SampleDesc.Quality = 0; 
depthStencilBufferDesc.Usage = D3D11_USAGE_DEFAULT; 
m_device->CreateTexture2D(&depthStencilBufferDesc, NULL, &m_depthStencilBuffer); 

// creating a depth stencil view 
HRESULT hr = m_device->CreateDepthStencilView( m_depthStencilBuffer, 
               NULL, 
               &m_depthStencilView); 


// setup depth stencil state. 
D3D11_DEPTH_STENCIL_DESC depthStencilStateDesc; 
ZeroMemory(&depthStencilStateDesc, sizeof(D3D11_DEPTH_STENCIL_DESC)); 

depthStencilStateDesc.DepthEnable = TRUE; 
depthStencilStateDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; 
depthStencilStateDesc.DepthFunc = D3D11_COMPARISON_LESS; 
depthStencilStateDesc.StencilEnable = FALSE; 

hr = m_device->CreateDepthStencilState(&depthStencilStateDesc, &m_depthStencilState); 

// setup rasterizer state. 
D3D11_RASTERIZER_DESC rasterizerDesc; 
ZeroMemory(&rasterizerDesc, sizeof(D3D11_RASTERIZER_DESC)); 

rasterizerDesc.AntialiasedLineEnable = FALSE; 
rasterizerDesc.CullMode = D3D11_CULL_BACK; 
rasterizerDesc.DepthBias = 0; 
rasterizerDesc.DepthBiasClamp = 0.0f; 
rasterizerDesc.DepthClipEnable = TRUE; 
rasterizerDesc.FillMode = D3D11_FILL_SOLID; 
rasterizerDesc.FrontCounterClockwise = FALSE; 
rasterizerDesc.MultisampleEnable = FALSE; 
rasterizerDesc.ScissorEnable = FALSE; 
rasterizerDesc.SlopeScaledDepthBias = 0.0f; 

// create the rasterizer state 
hr = m_device->CreateRasterizerState(&rasterizerDesc, &m_RasterizerState); 

m_deviceContext->OMSetRenderTargets(1, &m_renderTargetView, m_depthStencilView); 
m_deviceContext->OMSetDepthStencilState(m_depthStencilState, 1); 
m_deviceContext->RSSetState(m_RasterizerState); 

而这正是我使alpha混合:

D3D11_BLEND_DESC blendDescription; 
ZeroMemory(&blendDescription, sizeof(D3D11_BLEND_DESC)); 
blendDescription.RenderTarget[0].BlendEnable = TRUE; 
blendDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; 
blendDescription.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; 
blendDescription.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; 
blendDescription.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; 
blendDescription.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; 
blendDescription.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; 
blendDescription.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 
m_device->CreateBlendState(&blendDescription, &m_blendState); 
m_deviceContext->OMSetBlendState(m_blendState, 0, 0xffffffff); 

我知道,给无纹理的网格是一种纯白色完全不透明的纹理,可以以某种方式解决问题,但我怀疑深度测试存在问题。

当我使用D3D11_CREATE_DEVICE_DEBUG标志创建设备时,它不会给我任何错误或警告。

创建函数返回的所有HRESULT都是S_OK。

在此先感谢。

回答

0

要使混合工作,必须首先渲染所有完全不透明的对象,然后渲染具有透明度的所有对象。这意味着您的透明物体将根据距离摄像头较远的物体的距离进行排序。

理想情况下,您的不透明物体按照相反的方向(从前到后)进行排序,以便遮挡的像素被深度测试丢弃。

这通常是通过将所有绘制请求放入队列中完成的。一旦场景中的所有内容都在队列中,您可以根据各种因素对其进行排序,包括透明度,距离,材质等。然后,您可以循环排队,并按照正确的顺序制作所有抽奖请求。

对于简单的情况,只要确保首先绘制您的不透明物体,并且您的透明物体将在通常的前后订单中绘制。

+0

只是为了澄清一下,我设置我的深度测试和alpha混合的方式是否没有错? –

+0

他们看起来对我好。 – megadan

+0

如果您先渲染一个透明对象,它没有任何东西可以混合,所以它会显得不透明。它也会将它的z值写入深度缓冲区。如果您渲染的下一个对象位于透明对象的后面,那么由于深度测试将不会绘制被遮挡的像素,因为深度测试将只允许具有更接近z值的像素,然后当前位于深度缓冲区中。 – megadan