Alpha blending, deferred + forward pass issue

Started by
5 comments, last by lipsryme 11 years ago

I've got a deferred + forward pipeline working in my engine.

I'm drawing them "after" the GBuffer + lighting pass to the same scene target.

DepthWrite is enabled, AlphaBlend enabled and I'm drawing the backfaces first, then the front faces.

Still when I move the camera like this it's basically ignoring the depth test (or so it seems) and just blends this with the opaque object in front of it.

Blending is not enabled during GBuffer stage, only additive blending during lighting.

Here's the problem:

Cube on the left is transparent, right one opaque.

http://d.pr/i/yWIB

http://d.pr/i/hBmG

Transparent sorting itself works fine. The problem is only when they get in contact with opaque geometry in front of them.

Shouldn't the depth test tell it that this pixel should be discarded becaused the opaque geometry is in front of it ?

Transparents are being drawn "after" the opaques after all...

Here's how I draw them:


void RendererD3D11::RenderTransparents(const unsigned int* culledSceneIDs)
{
	// Set BlendState
	this->renderStateContext.SetBlendState(RenderStateDesc::AlphaBlend, &this->blendStates, this->deviceContext);

	// Set DepthStencilState
	this->renderStateContext.SetDepthStencilState(RenderStateDesc::DepthWriteEnabled, &this->depthStencilStates, this->deviceContext);


	// Set BackBuffer as RenderTarget & Main DepthStencil Buffer
	ID3D11DepthStencilView* main_DSV = this->mainDSV;
	ID3D11RenderTargetView* backbuffer_RTV = this->backBufferRTV;
	this->renderStateContext.SetRenderTargetSlot(backbuffer_RTV, main_DSV, this->deviceContext);

	for(size_t i = 0; i < this->contentManager->GetTransparentInstancesSize(); ++i)
	{
		if(this->contentManager->GetPtrToTransparentInstances()->at(i).entityType == SceneList::Primitive)
		{
			// Get ScenePrimitiveDescription
			unsigned int sceneID = this->contentManager->GetPtrToTransparentInstances()->at(i).sceneID;

			if(culledSceneIDs[sceneID] != 0)
			{
				ScenePrimitiveDescription* scenePrimitive = &this->sceneManager->GetCurrentScene()->GetDesc()->primitives[sceneID];


				// Set shader
				GenericShader* shader = NULL;
				switch(scenePrimitive->material.type)
				{
				case MaterialTypes::Glass:
					{
						shader = this->contentManager->GetShader(ShaderFile::Glass, this->device);
						break;
					}
				case MaterialTypes::GUI_AlphaBlend:
					{
						shader = this->contentManager->GetShader(ShaderFile::GUI_AlphaBlend, this->device);
						break;
					}
				case MaterialTypes::GUI_AlphaTest:
					{
						shader = this->contentManager->GetShader(ShaderFile::GUI_AlphaTest, this->device);
						break;
					}
				}

				if(shader)
				{
					this->deviceContext->VSSetShader(shader->VS, 0, 0);
					this->deviceContext->PSSetShader(shader->PS, 0, 0);
				}


				if(scenePrimitive->material.type == MaterialTypes::GUI_AlphaBlend ||
				   scenePrimitive->material.type == MaterialTypes::GUI_AlphaTest)
				{
					// Set DiffuseMap
					ID3D11ShaderResourceView* diffuseMap_SRV = this->contentManager->GetTextureFromPool(scenePrimitive->material.diffuseMap.ID)->GetResource();
					this->renderStateContext.SetResourceSlot(0, RenderStateDesc::PS, diffuseMap_SRV, this->deviceContext);

					// Update buffer
					D3D11_MAPPED_SUBRESOURCE mappedResourcePropertiesTransforms;

					// Lock the constant buffer so it can be written to
					this->deviceContext->Map(this->cbTransparentTransforms, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResourcePropertiesTransforms);

					// Get a pointer to the data in the constant buffer.
					cbsTransparentTransforms* pDataTransform = (cbsTransparentTransforms*)mappedResourcePropertiesTransforms.pData;

					// Copy the matrices into the constant buffer
					XMStoreFloat4x4(&pDataTransform->ViewProjection, mainCamera->ViewProjectionMatrix());

					XMMATRIX worldTransform = XMMatrixTranspose(XMLoadFloat4x4(&scenePrimitive->worldTransform));
					XMStoreFloat4(&pDataTransform->world_c0, worldTransform.r[0]);
					XMStoreFloat4(&pDataTransform->world_c1, worldTransform.r[1]);
					XMStoreFloat4(&pDataTransform->world_c2, worldTransform.r[2]);


					// Unlock the constant buffer
					this->deviceContext->Unmap(this->cbTransparentTransforms, 0);


					D3D11_MAPPED_SUBRESOURCE mappedResourceProperties;

					// Lock the constant buffer so it can be written to
					this->deviceContext->Map(this->cbGUITransforms, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResourceProperties);

					// Get a pointer to the data in the constant buffer.
					cbsGUITransforms* pData = (cbsGUITransforms*)mappedResourceProperties.pData;

					pData->TransparencyValue = 1.0f;

					// Unlock the constant buffer
					this->deviceContext->Unmap(this->cbGUITransforms, 0);

					// Set constant buffer
					this->deviceContext->VSSetConstantBuffers(0, 1, &this->cbTransparentTransforms);
					this->deviceContext->PSSetConstantBuffers(1, 1, &this->cbGUITransforms);


					// Draw call
					this->contentManager->GetPrimitiveFromPool(scenePrimitive->ID)->Draw(this->PosUVInputLayout, this->device,
																						 this->deviceContext, 0, 
																						 VertexDeclaration::PosUV);


					// Reset shader resource slots
					ID3D11ShaderResourceView* NullSRV = NULL;
					this->renderStateContext.SetResourceSlot(0, RenderStateDesc::PS, NullSRV, this->deviceContext);
				}
				else
				{
					// Set DiffuseMap
					ID3D11ShaderResourceView* diffuseMap_SRV = this->contentManager->GetTextureFromPool(scenePrimitive->material.diffuseMap.ID)->GetResource();
					this->renderStateContext.SetResourceSlot(0, RenderStateDesc::PS, diffuseMap_SRV, this->deviceContext);

					// Set NormalMap
					ID3D11ShaderResourceView* normalMap_SRV = this->contentManager->GetTextureFromPool(scenePrimitive->material.normalMap.ID)->GetResource();
					this->renderStateContext.SetResourceSlot(1, RenderStateDesc::PS, normalMap_SRV, this->deviceContext);

					// Set SpecularMap
					ID3D11ShaderResourceView* specularMap_SRV = this->contentManager->GetTextureFromPool(scenePrimitive->material.specularMap.ID)->GetResource();
					this->renderStateContext.SetResourceSlot(2, RenderStateDesc::PS, specularMap_SRV, this->deviceContext);

					// Set SamplerStates
					this->renderStateContext.SetSamplerState(RenderStateDesc::Anisotropic, &this->samplerstates, this->deviceContext, 0);
					this->renderStateContext.SetSamplerState(RenderStateDesc::Linear, &this->samplerstates, this->deviceContext, 1);


					// Update buffer
					D3D11_MAPPED_SUBRESOURCE mappedResourceProperties;

					// Lock the constant buffer so it can be written to
					this->deviceContext->Map(this->cbTransparentTransforms, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResourceProperties);

					// Get a pointer to the data in the constant buffer.
					cbsTransparentTransforms* pData = (cbsTransparentTransforms*)mappedResourceProperties.pData;

					// Copy the matrices into the constant buffer
					XMStoreFloat4x4(&pData->ViewProjection, mainCamera->ViewProjectionMatrix());

					XMMATRIX worldTransform = XMMatrixTranspose(XMLoadFloat4x4(&scenePrimitive->worldTransform));
					XMStoreFloat4(&pData->world_c0, worldTransform.r[0]);
					XMStoreFloat4(&pData->world_c1, worldTransform.r[1]);
					XMStoreFloat4(&pData->world_c2, worldTransform.r[2]);


					// Unlock the constant buffer
					this->deviceContext->Unmap(this->cbTransparentTransforms, 0);

					// Set Directional Light data
					D3D11_MAPPED_SUBRESOURCE mappedResourcePropertiesLighting;

					// Lock the constant buffer so it can be written to
					this->deviceContext->Map(this->cbLightData, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResourcePropertiesLighting);

					// Get a pointer to the data in the constant buffer.
					cbsDirectionalLightData* pDataLighting = (cbsDirectionalLightData*)mappedResourcePropertiesLighting.pData;

					pDataLighting->intensity = this->contentManager->GetDirectionalSunLight()->Intensity();
					XMFLOAT3 direction = this->contentManager->GetDirectionalSunLight()->Direction();
					XMFLOAT3 color = this->contentManager->GetDirectionalSunLight()->Color();
					pDataLighting->lightDir = direction;
					XMStoreFloat3(&pDataLighting->camPosition, this->mainCamera->Position());
					pDataLighting->padding = 0.0f;


					// Unlock the constant buffer
					this->deviceContext->Unmap(this->cbLightData, 0);



					// Set constant buffer
					this->deviceContext->VSSetConstantBuffers(0, 1, &this->cbTransparentTransforms);
					this->deviceContext->VSSetConstantBuffers(1, 1, &this->cbLightData);

					// Set FillMode
					if(this->isWireframe)
					{
						this->renderStateContext.SetRasterizerState(RenderStateDesc::Wireframe, &rasterizerStates, deviceContext);
					}
					else
					{
						this->renderStateContext.SetRasterizerState(RenderStateDesc::BackFaceCull, &rasterizerStates, deviceContext);
					}


					// Draw call
					this->contentManager->GetPrimitiveFromPool(scenePrimitive->ID)->Draw(this->PosUVNormalTangentInputLayout, this->device,
																						 this->deviceContext, 0, 
																						 VertexDeclaration::PosUVNormalTangent);

					// Set FillMode
					if(this->isWireframe)
					{
						this->renderStateContext.SetRasterizerState(RenderStateDesc::Wireframe, &rasterizerStates, deviceContext);
					}
					else
					{
						this->renderStateContext.SetRasterizerState(RenderStateDesc::FrontFaceCull, &rasterizerStates, deviceContext);
					}


					// Draw call
					this->contentManager->GetPrimitiveFromPool(scenePrimitive->ID)->Draw(this->PosUVNormalTangentInputLayout, this->device,
																						 this->deviceContext, 0, 
																						 VertexDeclaration::PosUVNormalTangent);


					// Reset shader resource slots
					ID3D11ShaderResourceView* NullSRV = NULL;
					this->renderStateContext.SetResourceSlot(0, RenderStateDesc::PS, NullSRV, this->deviceContext);
					this->renderStateContext.SetResourceSlot(1, RenderStateDesc::PS, NullSRV, this->deviceContext);
					this->renderStateContext.SetResourceSlot(2, RenderStateDesc::PS, NullSRV, this->deviceContext);
				}

			}
		}
		else
		{
			// StaticMesh in here...
		}
	}
}
Advertisement

Shouldn't the depth test tell it that this pixel should be discarded becaused the opaque geometry is in front of it ?

Yes, this should work. First render the opaque with depth test and depth write, then render the (sorted) transparent geometry with only depth test. Therefor check your depth test/write parameters.

Wait so the transparent geometry should not be rendered with depth write ? But how would that work if there wasn't any geometry in the Z-Buffer for this transparent object ?

update: Hmm doesn't seem to do anything.

Is your depth-stencil the same one that was bound while the g-buffer was being drawn (and has there be no clears since then)?

You're right I found the problem. I automated my set render target call and forgot to check on depth stencil changes, and instead it only checked if the RT was changed in between. So in the end it was set to NULL when rendering the transparent objects.

Got it fixed now works great. But why do I not need depth write ?

Won't there be problems ?

Update: Oh I see...because we already draw them by their order from back to front we don't need the depth buffer to check if there's another transparent object in front of it.

Yeah if the scene is correctly ordered, then it doesn't matter if you have it on or off.

Is it possible to include transparent geometry in the lighting pass ?

I'm having a problem now because I'm calculating some atmospheric scattering (sunlight and sky) in there but this will not work on my forward shaded transparent geometry afterwards, and to calculate it again for each transparent object would be crazy.

This topic is closed to new replies.

Advertisement