为什么渲染到纹理会导致透明度?

作为一个快速的背景,这是在我用C#编写的SharpDX框架的自定义游戏引擎的上下文中。 在引擎中,当我渲染UI时,我通过创建一个具有渲染目标纹理的canvas对象来实现。 我渲染到该纹理,将此纹理包裹在canvas四边形上,然后将canvas呈现给世界。 作为一个说明,我正在使用向前渲染,不推迟。

但问题是,canvas渲染的纹理,但我的UItesting面板的实际渲染纹理,生成一个透明的补丁,而不是所需的面板。 以下是我所描述的屏幕截图:

在这里输入图像描述

现在为了testing,后台缓冲区被清除为红色,我试图用testing图像将面板渲染到它的中心。 正如你所看到的,红色的后台缓冲区很好地渲染到了canvas上,但是我渲染到面板的testing图像是透明渲染的。 我使用相同的shaders / hlsl文件在canvas上渲染canvas和面板,所以我怀疑这是问题的根源。

下面是一个代码片段,用于渲染我的canvasarrays,这可能有助于:

//start preparing matrix buffer viewMatrix = activeCamera.GetViewMatrix(); MatrixBuffer matrices = new MatrixBuffer(); matrices.viewMatrix = Matrix.Transpose(viewMatrix); matrices.projMatrix = Matrix.Transpose(DXEnv.orthoProjectionMatrix); //change context if needed, and draw using the shader if (activeShader != ShaderID.TEXTURE_UNLIT) { textureUnlitShader.SetActive(DXEnv.device, DXEnv.context); activeShader = ShaderID.TEXTURE_UNLIT; } for (int i=0 ; i< canvases.Length; i++) { //clear render depth/render target & set the render-to-texture target DXEnv.context.ClearDepthStencilView(DXEnv.depthView, D3D11.DepthStencilClearFlags.Depth, 1, 0); DXEnv.context.ClearRenderTargetView(canvases[i].renderTarget, new Color4(1.0f, 0.0f, 0.0f, 1.0f)); DXEnv.SetNewRenderTarget(canvases[i].renderTarget); //recursively render to the new texture textureUnlitShader.SetTextureResource(DXEnv.device, DXEnv.context, canvases[i].source); RenderPanelRecursive(canvases[i].root, matrices); canvases[i].CalculateModelMatrix(transforms[i]); matrices.modelMatrix = Matrix.Transpose(canvases[i].modelMatrix); //set texture to the new resource and reset render view, then render canvas DXEnv.SetNewRenderTarget(DXEnv.renderView); //TODO: batchh up canvas rendering to minimize context switch textureUnlitShader.SetTextureResource(DXEnv.device, DXEnv.context, canvases[i].shaderTexture); //this is the line i tried commenting out textureUnlitShader.UpdateShader(DXEnv.device, DXEnv.context, matrices, canvases[i]); } 

调用textureUnlitShader.UpdateShader(...)很可能不是我find的问题。 我试着评论在上面的代码中设置的textureUnlitShader.SetTextureResource(..., canvases[i].shaderTexture) ,并且,如预期的那样,渲染到纹理缓冲区被渲染到canvas上,我的testing图像被呈现给canvas。 但有趣的是,这个洞仍然存在。 这导致我相信面板实际上并没有正确渲染到canvas的纹理。 相反,它似乎是以某种方式单独呈现的。 这导致我相信,最有可能的罪魁祸首是我实施渲染到纹理技术的方式,这是不知何故。 下面是这种情况的截图:

在这里输入图像描述

我调用渲染面板recursion看起来有点像canvas的渲染调用,但它如下所示:

  private void RenderPanelRecursive(Panel p, MatrixBuffer matrices) { //render lowest level to highest level to preserve order if ( (p.active == true) && (p.renderable == true)) { ImagePanel castP = p as ImagePanel; castP.CalculateModelMatrix(); matrices.modelMatrix = Matrix.Transpose(castP.modelMatrix); textureUnlitShader.UpdateShader(DXEnv.device, DXEnv.context, matrices, castP); //perhaps build this into the shader instead? } //recurse down further if more children exist if (p.currentNumberControls != 0) { for (int i = 0; i < p.currentNumberControls; i++) { RenderPanelRecursive(p.children[i], matrices); } } } 

我不认为小组本身可能会出错。 matrix常量缓冲区似乎正在写入正确,因为面板呈现在canvas上的正确位置。 顶点位置/ uv-coord常量缓冲区与canvas顶点位置/ uv-coord常量缓冲区的结构相同。 为了确保这一点,我已经多次阅读了这个部分,并通过设置一些中断点来确保这些缓冲区正确写入。 没有什么比平常更突出的了。

这让我回到我之前的说法,可能是我设置渲染到纹理的方式是错误的。

预先感谢您提供的任何帮助。

我尝试先做一些事情来debugging它。 对于你的用户界面只需设置像素着色器写出白色与alpha设置为1.0f。 如果这是渲染,不再透明,那么你可以本地化。 但如果不是,我也会看看你的混合状态。 我假设你的用户界面不使用zbuffer? 如果是,那么每一帧都清零? 你正在渲染一些东西,所以它不在几何graphics中。

我用一个类似的方法来处理你在UI中做的事情。 我发现只是通过你通常发现问题的方法。 如果不能再发布,我会尝试并考虑其他可能性

如果有人遇到类似的问题,我会分享最终解决问题的方法。 我采取了ErnieDingo的建议,仔细研究了z-buffer。 寻找我的Z缓冲区错误的东西,我碰到了这个线程 ,这让我想起了我已经忘记了一个至关重要的细节。

在上面的代码中,我为每个canvas使用了相同的z缓冲区,这可以在调用ClearDepthStencilView(DXEnv.depthBuffer, ...)看到。 除此之外,z缓冲区不能在不同尺寸的渲染目标之间共享,因为缓冲区是根据特定的大小创建的。 这是机器中的猴子扳手,所以我给每个canvas自己的z缓冲区,并附加一个独特的深度模板视图到每个z缓冲区。

这个for循环的新代码看起来像这样(我也继续,我的渲染到纹理调用和我的canvas渲染,以避免在目标之间过度切换):

  for (int i = 0; i < canvases.Length; i++) { if (canvases[i] != null && canvases[i].active) { //set the new render target to be the canvas, and set texture to be the spritesheet DXEnv.context.ClearRenderTargetView(canvases[i].renderTarget, new Color4(1.0f, 0.0f, 0.0f, 1.0f)); DXEnv.context.ClearDepthStencilView(canvases[i].depthView, D3D11.DepthStencilClearFlags.Depth, 1, 0); DXEnv.SetNewRenderTarget(canvases[i].renderTarget, canvases[i].depthView); //recursively render to the new texture textureUnlitShader.SetTextureResource(DXEnv.device, DXEnv.context, canvases[i].source); RenderPanelRecursive(canvases[i].root, matrices); } } DXEnv.SetNewRenderTarget(DXEnv.renderView, DXEnv.depthView); for (int i = 0; i < canvases.Length; i++) { if (canvases[i] != null && canvases[i].active) { canvases[i].CalculateModelMatrix(transforms[i]); //TODO: return types make this more intuitive matrices.modelMatrix = Matrix.Transpose(canvases[i].modelMatrix); //set texture to the new resource and reset render view, then render canvas textureUnlitShader.SetTextureResource(DXEnv.device, DXEnv.context, canvases[i].shaderTexture); textureUnlitShader.UpdateShader(DXEnv.device, DXEnv.context, matrices, canvases[i]); } } 

注意 :上面的代码没有展示我的不同尺寸的渲染目标也需要不同的投影matrix才能正确渲染。 如果你有不同大小的渲染目标,每个渲染目标也将需要自己的本地化投影matrix,只是为了logging。

谢谢您的帮助。