XNA / MonoGame – 使用模板缓冲区问题渲染透明背景(3d)

我正在尝试使用以下属性渲染三维纹理四边形:

  1. 随着照明(排除“AlphaTestEffect”)。
  2. 透明的背景(没有不透明度水平,只是二进制不透明或透明)。
  3. 没有sorting,例如,我不想按照相机距离sorting对象。

如果我只是试图用透明背景定期渲染四边形,结果是即使是透明像素被写入到深度缓冲区,这导致后台错误,看到图片:

在这里输入图像描述

所以我尝试用不同的方式来使用模板缓冲区。 我做的是以下几点:

  1. 只渲染模板缓冲区上的透明像素,以创建一个遮罩。
  2. 再次使用之前创建的模板缓冲区来渲染纹理本身。

现在它可以与背景渲染一起使用,但问题是具有透明背景的不同四边形在透明像素中彼此隐藏,如下所示:

在这里输入图像描述

我不确定这是因为模板缓冲区没有在渲染之间清除,或者可能是我错误地写入深度的一个步骤?

无论如何,这是我的代码(至less是它的相关部分):

// set effect and settings for the stencil mask phase _alphaMaskEffect = new AlphaTestEffect(device); _alphaMaskEffect.World = Matrix.Identity; _alphaMaskEffect.AlphaFunction = CompareFunction.Equal; _alphaMaskEffect.ReferenceAlpha = 0; _alphaMaskEffect.VertexColorEnabled = true; _alphaMaskEffect.DiffuseColor = Color.White.ToVector3(); _alphaRenderStencilMaskSettings = new DepthStencilState { StencilEnable = true, StencilFunction = CompareFunction.Always, StencilPass = StencilOperation.Replace, ReferenceStencil = 1, DepthBufferEnable = true, DepthBufferWriteEnable = false, }; // set settings for the regular rendering phase _alphaRenderTextureWithStencilSettings = new DepthStencilState { StencilEnable = true, StencilFunction = CompareFunction.Equal, StencilPass = StencilOperation.Keep, ReferenceStencil = 0, DepthBufferEnable = true, DepthBufferWriteEnable = true, }; 

这里是draw函数本身:

 // set settings for the stencil buffer rendering device.DepthStencilState = _alphaRenderStencilMaskSettings; // render stencil buffer foreach (EffectPass pass in _alphaMaskEffect.CurrentTechnique.Passes) { // draw current pass pass.Apply(); device.DrawUserIndexedPrimitives <VertexPositionNormalTexture>( PrimitiveType.TriangleList, Vertices, 0, 4, Indexes, 0, 2); } // now render the quad with the stencil buffer device.DepthStencilState = _alphaRenderTextureWithStencilSettings; // render effect itself foreach (EffectPass pass in _effect.CurrentTechnique.Passes) { // draw current pass pass.Apply(); device.DrawUserIndexedPrimitives <VertexPositionNormalTexture>( PrimitiveType.TriangleList, Vertices, 0, 4, Indexes, 0, 2); } 

tl; dr什么是正确的方式来渲染三维四边形透明背景,照明,没有sorting对象的距离相机? 如果这是我尝试的代码 – 我该如何让渲染停止隐藏对方?

嘿交配最好的办法是用alphatesting,这种方式没有sorting,但它仍然有助于sorting,你可以做照明,呈现不透明的混合状态,剔除模式为无。

我这样做我的草,它只是一个阿尔法testing,然后我在阴影中建立所有正常的数据。 我也使用vface语义翻转正常,因为它的双面。

像素着色器中的alphatesting:

  diffuseLayer = DiffuseMaps.Sample(samANISOTROPICClamp, float3(input.TexCoord, input.TextureID)); clip(diffuseLayer.a - 0.18); // 0.18 is the alpha cut off, play with this 

基于vface翻转法线:

  float3 normalViewSpace = NormalMapToSpaceNormal(NormalLayer.rgb, TBN[2], TBN[1], TBN[0]); normalViewSpace = input.vFace ? normalViewSpace : -normalViewSpace; // ignore the viewsapce stuff that is for my deferred render 

(N应该是float3(0,1,0),UV应该是剪辑空间xy,P应该是世界空间位置:

 float3x3 cotangent_frame(float3 N, float3 p, float2 uv) { // get edge vectors of the pixel triangle float3 dp1 = ddx_fine(p); float3 dp2 = ddy_fine(p); float2 duv1 = ddx_fine(uv); float2 duv2 = ddy_fine(uv); // solve the linear system float3 dp2perp = cross(dp2, N); float3 dp1perp = cross(N, dp1); float3 T = dp2perp * duv1.x + dp1perp * duv2.x; float3 B = dp2perp * duv1.y + dp1perp * duv2.y; // construct a scale-invariant frame float invmax = -sqrt(max(dot(T, T), dot(B, B))); return float3x3(T * invmax, B * invmax, N); } 

草地可以是这样的:

在这里输入图像描述

CPU绘制代码(与DX11我不必设置顶点缓冲区(运行时生成的点):

  _Context.InputAssembler.SetVertexBuffers(0, Nothing, Nothing) _Context.InputAssembler.InputLayout = Nothing _Context.OutputMerger.DepthStencilState = _device.RenderStates.Default _Context.Rasterizer.State = _device.RenderStates.CullNone _Context.SetBlendState(_device.RenderStates.Opaque) GrassEffectVars.Set("View", _camera.EyeTransform) GrassEffectVars.Set("Projection", _camera.ProjectionTransform) GrassEffectVars.Set("GrassNodes", GrassNodesView) GrassEffectVars.Set("DiffuseMaps", GrassTextureArraySRV) GrassEffectVars.Set("NormalMaps", GrassNormalTextureArraySRV) GrassEffectVars.Set("CameraTransform", _camera.Transform) GrassEffectVars.Set("gEyePosW", _camera.CameraBounds.Center) GrassEffectVars.Set("FarClip", _camera.FarClip) _Context.InputAssembler.SetIndexBuffer(indexBuffer, Format.R32_UInt, 0) _Context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList GrassEffectVars.Set("InvView", _camera.Transform) GrassEffectVars.Set("WorldViewProj", _camera.EyeProjectionTransform) _Context.ApplyShader(GrassEffectPass2) _Context.DrawIndexedInstanced(6, GrassCount, 0, 0, 0) 

全草着色器问(从点建立四边形):

 struct PS_INPUT3 { float4 Position : SV_POSITION; float2 TexCoord : TEXCOORD0; uint TextureID : TextureID; float4 Depth : VS_DEPTH; bool vFace : SV_IsFrontFace; }; PS_INPUT2 VS_Main2(uint id : SV_VertexID, uint instid : SV_InstanceId) { PS_INPUT2 output = (PS_INPUT2) 0; uint particleIndex = id / 4; uint vertexInQuad = id % 4; GrassNode Grass = GrassNodes[instid]; float3 WS_Position = Grass.Pos.xyz; float4 Data = Grass.Data; float3 position; position.x = (vertexInQuad % 2) ? 1.0 : -1.0; position.y = (vertexInQuad & 2) ? -1.0 : 1.0; position.z = 0.0; position.xy *= Data.y; WS_Position.y += Data.y; WS_Position.x += Data.z; WS_Position.z += Data.w; position = mul(position, (float3x3) InvView) ; WS_Position = WS_Position.xyz + position; output.Depth.xyz = WS_Position; output.Depth.w = mul(float4(WS_Position, 1), View).z; output.Position = mul(float4(WS_Position.xyz, 1.0), WorldViewProj); output.TexCoord.x = (vertexInQuad % 2) ? 1.0 : 0.0; output.TexCoord.y = (vertexInQuad & 2) ? 1.0 : 0.0; output.TextureID = Data.x; return output; } GBufferPixelShaderOutput PS_Main2(PS_INPUT3 input) { GBufferPixelShaderOutput output; float4 diffuseLayer = 0; float4 NormalLayer = 0; diffuseLayer += DiffuseMaps.Sample(samANISOTROPICClamp, float3(input.TexCoord, input.TextureID)); clip(diffuseLayer.a - 0.18); NormalLayer += NormalMaps.Sample( samANISOTROPICClamp, float3(input.TexCoord, input.TextureID)) ; float3x3 TBN = cotangent_frame(float3(0, 0.957, 0), input.Depth.xyz, input.Position.xy); TBN[2] = normalize(mul(TBN[2], (float3x3) View)); TBN[0] = normalize(mul(TBN[0], (float3x3) View)); TBN[1] = normalize(mul(TBN[1], (float3x3) View)); float3 normalViewSpace = NormalMapToSpaceNormal(NormalLayer.rgb, TBN[2], TBN[1], TBN[0]); normalViewSpace = input.vFace ? normalViewSpace : -normalViewSpace; output.Color = float4(diffuseLayer.rgb, diffuseLayer.r); output.RenderMaterialID = matID; output.Depth = float4(-input.Depth.w / FarClip, 0, EncodeNormal(normalViewSpace.xyz)); return output; }