2017-05-06 124 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