补充提一句关于渲染管线可以绑定的状态主要有如下四种:
- 光栅化状态(光栅化阶段)
- 采样器状态(像素着色阶段)
- 混合状态(输出合并阶段)
- 深度/模板状态(输出合并阶段)

一、混合(Blending)

对于两个相同位置的像素点,规定Csrc为源像素的颜色(从像素着色器输出的像素),Cdst为目标像素的颜色(已经存在于后备缓冲区上的像素)。在Direct3D中使用下面的混合等式来将源像素色和目标像素色进行混合。
1.1 创建混合状态
ID3D11Device::CreateBlendState方法–创建混合状态
在创建混合状态前,需要填充D3D11_BLEND_DESC结构体:
typedef struct D3D11_BLEND_DESC
{
BOOL AlphaToCoverageEnable; // 默认关闭,这里
BOOL IndependentBlendEnable; // 是否每个渲染目标都有独立的混合混合描述,关闭的话都使用索引为0的描述信息
D3D11_RENDER_TARGET_BLEND_DESC RenderTarget[ 8 ];
} D3D11_BLEND_DESC;
typedef struct D3D11_RENDER_TARGET_BLEND_DESC
{
BOOL BlendEnable; // 是否开启混合
D3D11_BLEND SrcBlend; // 源颜色混合因子
D3D11_BLEND DestBlend; // 目标颜色混合因子
D3D11_BLEND_OP BlendOp; // 颜色混合运算符
D3D11_BLEND SrcBlendAlpha; // 源Alpha混合因子
D3D11_BLEND DestBlendAlpha; // 目标Alpha混合因子
D3D11_BLEND_OP BlendOpAlpha; // Alpha混合运算符
UINT8 RenderTargetWriteMask; // D3D11_COLOR_WRITE_ENABLE枚举类型来指定可以写入的颜色
} D3D11_RENDER_TARGET_BLEND_DESC;
混合运算符的设置
对于运算符 ⊞ 的含义,可以使用下面的枚举类型D3D11_BLEND_OP来描述:

你可以分开指定运算颜色和Alpha通道的运算符。
混合因子的设置
对于混合公式,我们可以按需要设置混合因子。混合因子使用枚举类型D3D11_BLEND类型进行描述:

其中sat函数将值限定在[0.0, 1.0]之间。
可写入的颜色
枚举类型RenderTargetWriteMask有如下枚举值:

若你想指定红色和ALPHA通道可以写入,可以用位运算与结合起来,即D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_ALPHA
ID3D11Device::CreateBlendState含义如下:
HRESULT ID3D11Device::CreateBlendState(
const D3D11_BLEND_DESC *pBlendStateDesc, // [In]混合状态描述
ID3D11BlendState **ppBlendState); // [Out]输出混合状态
1.2 输出合并阶段设置混合状态
ID3D11DeviceContext::OMSetBlendState方法–输出合并阶段设置混合状态
方法如下:
void ID3D11DeviceContext::OMSetBlendState(
ID3D11BlendState *pBlendState, // [In]混合状态,如果要使用默认混合状态则提供nullptr
const FLOAT [4] BlendFactor, // [In]混合因子,如不需要可以为nullptr
UINT SampleMask); // [In]采样掩码,默认为0xffffffff
默认混合状态如下:
AlphaToCoverageEnable = false;
IndependentBlendEnable = false;
RenderTarget[0].BlendEnable = false;
RenderTarget[0].SrcBlend = D3D11_BLEND_ONE
RenderTarget[0].DestBlend = D3D11_BLEND_ZERO
RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD
RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE
RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO
RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD
RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL
采样掩码的设置主要是针对多重采样的操作,若采样掩码的第i位为0,则对应第i次采样将不进行,但这得在实际上进行不小于i次的采样时才会起作用。通常情况下设为0xffffffff来允许所有采样操作。
二、深度/模板测试(Depth/Stenciling)
深度测试、模板测试的执行是在混合操作之前执行的,具体的执行顺序为:模板测试→深度测试→混合操作。
深度测试
深度测试需要用到深度/模板缓冲区,对每个像素使用24位或32位来映射物体从世界到NDC坐标系下z的值(即深度,范围[0.0, 1.0])。0.0时达到摄像机的最近可视距离,而1.0时达到摄像机的最远可视距离。若某一像素位置接收到多个像素片元,只有z值最小的像素才会通过最终的深度测试。具体细化的话,就是现在有一个像素片元,已知它的深度值,然后需要跟深度缓冲区中的深度值进行比较,若小于深度缓冲区的深度值,则该像素片元将会覆盖后备缓冲区原来的像素片元,并更新深度缓冲区中对应位置的深度值。
模板测试
除了深度测试以为,我们还可以设定模板测试来阻挡某些特定的区域的像素通过后备缓冲区。而且模板测试在操作上自由度会比深度测试大。对于需要进行模板测试的像素,比较式如下:
(StencilRef & StencilReadMask) ⊴ (Value & StencilReadMask)
该表达式首先括号部分是两个操作数进行与运算,然后通过⊴(用户指定的运算符)对两个结果进行比较。若该表达式的值为真,则最终通过模板测试,并保留该像素进行后续的混合操作。
其中StencilReadMask则是应用程序所提供的掩码值。
深度/模板格式
深度/模板缓冲区是一个2D数组(纹理),它必须经由确定的数据格式创建:
- DXGI_FORMAT_D32_FLOAT_S8X24_UINT:每个元素占64位,其中32位浮点数用于深度测试,8位无符号整数用于模板测试,剩余24位仅用于填充。
- DXGI_FORMAT_D24_UNORM_S8_UINT:每个元素占32位,其中24位无符号整数映射到深度值[0.0,1.0]的区间,8位无符号整数用于模板测试。
2.1、清空深度/模板缓冲区
ID3D11DeviceContext::ClearDepthStencilView方法–深度/模板缓冲区内容清空
方法原型如下:
void ID3D11DeviceContext::ClearDepthStencilView(
ID3D11DepthStencilView *pDepthStencilView, // [In]深度模板视图
UINT ClearFlags, // [In]使用D3D11_CLEAR_FLAG枚举类型决定需要清空的部分
FLOAT Depth, // [In]使用Depth值填充所有元素的深度部分
UINT8 Stencil); // [In]使用Stencil值填充所有元素的模板部分
其中D3D11_CLEAR_FLAG有如下枚举值:


本文详细介绍了Direct3D11中的渲染管线中混合、深度/模板测试的状态设置,包括混合因子、深度测试、模板测试的原理与配置。并展示了如何利用这些技术实现平面镜的反射效果,强调了绘制顺序和模板缓冲区的重要性。

3199

被折叠的 条评论
为什么被折叠?



