如何在渲染 3D 场景之前在 3D 场景之上渲染 2D UI?

问题描述

我有一个包含 2D 叠加层的 2D 纹理。纹理本身大部分是空白(透明),有一些部分包含一些数据。

我目前所做的是渲染整个 3D 场景,禁用深度缓冲区并在其上渲染 2D 四边形:

 // render 3D scene
 context->OMSetDepthStencilState(_noDepthTestState.Get(),1); // disable depth test
 // render 2D quad on top of the whole viewport
 context->OMSetDepthStencilState(nullptr,1); // restore default

_noDepthTestState 变量是使用以下描述符创建的 ID3D11DepthStencilState

   D3D11_DEPTH_STENCIL_DESC desc{};
   desc.DepthEnable = false;
   desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
   desc.DepthFunc = D3D11_COMPARISON_LESS;
   desc.StencilEnable = true;
   desc.StencilReadMask = 0xFF; 
   desc.StencilWriteMask = 0xFF;
   desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
   desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
   desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
   desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
   desc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
   desc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
   desc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
   desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

我想在渲染 3D 场景之前渲染四边形 2D 叠加层,并且 3D 对象将仅在 2D 叠加层为空白的地方绘制。

有没有一种有效的方法来实现这种行为?深度/模板状态的正确配置是什么?

解决方法

这取决于您的主要 3D 场景的渲染方式。

假设您不使用模板缓冲区,并且使用 D3D11_COMPARISON_LESS 深度比较,请按以下方式绘制四边形。

您的顶点着色器应输出四边形顶点 [ ±1,±1,1 ]。这使得 GUI 离相机最近,早期的 Z 拒绝应该在 PS 阶段之前裁剪 3D 场景中被遮挡的像素,节省一些 GPU 资源(我假设这就是你想要先渲染 2D 的原因)。

您的像素着色器应该读取您的 GUI 纹理,将 alpha 与某个阈值进行比较,如果它足够小,则调用 discard。丢弃的像素不会改变任何缓冲区,无论是颜色还是深度/模板。

如果您的 GUI 由轴对齐的矩形组成,或者您不使用 MSAA,这将正常工作。但是,如果您的 GUI 确实有弯曲/对角线边缘,并且使用 MSAA,您将不会对结果感到满意。解决这个问题是可能的,但要复杂得多。在渲染 GUI 纹理时,您需要以某种方式生成每像素 SV_Coverage 值。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...