混合运算
typedef enum D3D12_BLEND_OP {
D3D12_BLEND_OP_ADD = 1, //添加源 1 和源 2。
D3D12_BLEND_OP_SUBTRACT = 2,//从源 2 中减去源 1。
D3D12_BLEND_OP_REV_SUBTRACT = 3,//从源 1 中减去源 2。
D3D12_BLEND_OP_MIN = 4,//查找源 1 和源 2 的最小值。
D3D12_BLEND_OP_MAX = 5//查找源 1 和源 2 的最大值。
} ;
运行时单独实现 RGB 混合和 alpha 混合。 因此,混合状态需要针对 RGB 数据和 alpha 数据执行单独的混合操作。 这些混合操作在 D3D12_RENDER_TARGET_BLEND_DESC 结构中指定。 混合块图中显示了两个源(源 1 和源 2)。
混合状态由 输出合并阶段 使用,以确定如何将两个 RGB 像素值和两个 alpha 值混合在一起。 两个 RGB 像素值和两个 alpha 值是像素着色器输出的 RGB 像素值和已位于输出呈现目标中的 RGB 像素值和 alpha 值。 D3D12_BLEND值控制混合阶段用来调节像素着色器、呈现目标或两者的值的数据源。 D3D12_BLEND_OP值控制混合阶段如何以数学方式合并这些调节值。
在求取最小值或最大值(min/max )的运算中会忽略混合因子。
irect3D从最近几版开始加入了一项新特性,通过逻辑运算符对源颜色和目标颜色进行混合,用以 取代上述传统的混合方程。这些逻辑运算符如下:
enum D3D12_LOGIC_OP
{
D3D12_LOGIC_OP_CLEAR = 0,//清除呈现目标
D3D12_LOGIC_OP_SET = ( D3D12_LOGIC_OP_CLEAR + 1 ) ,//设置呈现目标
D3D12_LOGIC_OP_COPY = ( D3D12_LOGIC_OP_SET + 1 ) ,//从像素着色器输出) 复制呈现目标 (源。
D3D12_LOGIC_OP_COPY_INVERTED = ( D3D12_LOGIC_OP_COPY + 1 ) ,//执行呈现目标 () ~s 的倒排副本。
D3D12_LOGIC_OP_NOOP = ( D3D12_LOGIC_OP_COPY_INVERTED + 1 ) ,//在呈现目标视图中 (d 目标) 中,不会对呈现目标执行任何操作
D3D12_LOGIC_OP_INVERT = ( D3D12_LOGIC_OP_NOOP + 1 ) ,//反转呈现目标 (~d) 。
D3D12_LOGIC_OP_AND = ( D3D12_LOGIC_OP_INVERT + 1 ) ,//对呈现目标执行逻辑 AND 操作, (s & d) 。
D3D12_LOGIC_OP_NAND = ( D3D12_LOGIC_OP_AND + 1 ) ,//对呈现目标执行逻辑 NAND 操作 (~(s & d)) 。
D3D12_LOGIC_OP_OR = ( D3D12_LOGIC_OP_NAND + 1 ) ,//对呈现目标执行逻辑 OR 操作 (s
D3D12_LOGIC_OP_NOR = ( D3D12_LOGIC_OP_OR + 1 ) ,//对呈现目标执行逻辑 NOR 操作 (~ (s
D3D12_LOGIC_OP_XOR = ( D3D12_LOGIC_OP_NOR + 1 ) ,//对呈现目标执行逻辑 XOR 操作 () s ^ d 。
D3D12_LOGIC_OP_EQUIV = ( D3D12_LOGIC_OP_XOR + 1 ) ,//对呈现目标执行逻辑相等操作 (~(s ^ d)) 。
D3D12_LOGIC_OP_AND_REVERSE = ( D3D12_LOGIC_OP_EQUIV + 1 ) ,//对呈现目标执行逻辑 AND 和反向操作, (s & ~d) 。
D3D12_LOGIC_OP_AND_INVERTED = ( D3D12_LOGIC_OP_AND_REVERSE + 1 ) ,//对呈现目标执行逻辑 AND 和反转操作 (~s & d) 。
D3D12_LOGIC_OP_OR_REVERSE = ( D3D12_LOGIC_OP_AND_INVERTED + 1 ) ,//对呈现目标执行逻辑 OR 和反向操作 (s
D3D12_LOGIC_OP_OR_INVERTED = ( D3D12_LOGIC_OP_OR_REVERSE + 1 ) //对呈现目标执行逻辑 OR 和反转操作 (~s
}
此枚举由 D3D12_RENDER_TARGET_BLEND_DESC 结构使用。
注意,不能同时使用传统混合方程与逻辑运算符这两种混合手段,两者只能择其一。另外需要指岀 的是,为了使用逻辑运算符混合技术,就一定要选择它所支持的渲染目标格式一 个格式应当为UINT (无符号整数)的有关类型,否则我们会收到错误提示信息。
混合因子
enum D3D12_BLEND
{
D3D12_BLEND_ZERO = 1,//混合因子 (0、0、0、0) 。 无预混合操作。
D3D12_BLEND_ONE = 2,//混合因子 (为 1、1、1、1) 。 无预混合操作。
D3D12_BLEND_SRC_COLOR = 3,//混合因子为 (Rs、Gs、Bs、As) ,即像素着色器 (RGB) 的颜色数据。 无预混合操作。
D3D12_BLEND_INV_SRC_COLOR = 4,//混合因子 (为 1 - Rs、1 - Gs、1 - Bs、1 -) ,即像素着色器 (RGB) 的颜色数据。 预混合操作将反转数据,生成 1 - RGB。
D3D12_BLEND_SRC_ALPHA = 5,//混合因子 (As、As、As、As) ,即像素着色器 (A) 的 alpha 数据。 无预混合操作。
D3D12_BLEND_INV_SRC_ALPHA = 6,//混合因子 (为 1 - As、1 - As、1 - As、1 - As、1 - As) ,即从像素着色器 (A) 的 alpha 数据。 预混合操作将反转数据,生成 1 - A。
D3D12_BLEND_DEST_ALPHA = 7,//混合因子 (Ad A dAd Ad) ,即呈现器目标的 alpha 数据。 无预混合操作。
D3D12_BLEND_INV_DEST_ALPHA = 8,//混合因子 (1 - Ad 1 - Ad 1 - Ad 1 - Ad) ,即来自呈现目标的 alpha 数据。 预混合操作将反转数据,生成 1 - A。
D3D12_BLEND_DEST_COLOR = 9,//混合因子 (Rd、Gd、Bd、Ad) ,即来自呈现器目标的颜色数据。 无预混合操作。
D3D12_BLEND_INV_DEST_COLOR = 10,//混合因子 (1 - Rd、1 - Gd、1 - Bd、1 - Ad) ,即来自呈现器目标的颜色数据。 预混合操作将反转数据,生成 1 - RGB。
D3D12_BLEND_SRC_ALPHA_SAT = 11,混合因子为 (f、f、f、1) ;其中 f = min (As, 1- Ad) 。 预混合操作将数据固定到 1 或更少
D3D12_BLEND_BLEND_FACTOR = 14,//混合因子是ID3D12GraphicsCommandList::OMSetBlendFactor 的混合因子集。 无预混合操作。
D3D12_BLEND_INV_BLEND_FACTOR = 15,//混合因子是 ID3D12GraphicsCommandList::OMSetBlendFactor 的混合因子集。 预混合运算将反转混合因子,生成 1 - blend_factor。
D3D12_BLEND_SRC1_COLOR = 16,//混合因子是数据源,既作为像素着色器输出的颜色数据。 没有预混合操作。 此混合因子支持双源颜色混合。
D3D12_BLEND_INV_SRC1_COLOR = 17,混合因子是数据源,既作为像素着色器输出的颜色数据。 预混合操作将反转数据,生成 1 - RGB。 此混合因子支持双源颜色混合。
D3D12_BLEND_SRC1_ALPHA = 18,混合因子是像素着色器作为 alpha 数据输出的数据源。 没有预混合操作。 此混合因子支持双源颜色混合。
D3D12_BLEND_INV_SRC1_ALPHA = 19,混合因子是像素着色器作为 alpha 数据输出的数据源。 预混合操作将反转数据,生成 1 - A。此混合因子支持双源颜色混合。
D3D12_BLEND_ALPHA_FACTOR = 20,混合因子 (A、A、A) ,其中常量 A 取自 OMSetBlendFactor 的混合因子集。若要在目标计算机上成功使用此常量,从 ID3D12Device::CheckFeatureSupport返回的D3D12_FEATURE_DATA_D3D12_OPTIONS13必须将其 AlphaBlendFactorSupported 设置为 TRUE。
D3D12_BLEND_INV_ALPHA_FACTOR= 21,混合因子 (为 1 – A、1 – A、1 – A、1 – A、1 – A) ,其中常量 A 取自 OMSetBlendFactor 的混合因子集。若要在目标计算机上成功使用此常量,从ID3D12Device::CheckFeatureSupport返回的D3D12_FEATURE_DATA_D3D12_OPTIONS13必须将其 AlphaBlendFactorSupported 设置为 TRUE。
}
上述的混合因子皆可运用于RGB混合方程。但对于alpha混合方程来说,却不可使用以.COLOR作 为结尾的混合因子。
我们可以用下列函数来设置混合因于:
void ID3D12GraphicsCommandList::OMSetBlendFactor(const FLOAT BlendFactor[ 4 ]);若传入nullptr,则恢复值为(1, 1, 1> 1)的默认混合因子。
混合状态
D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
为了配置非默认混合状态,我们必须填写D3D12_BLEND_DESC结构体。该结构体的定义如下。
typedef struct D3D12_BLEND_DESC (
BOOL AlphaToCoverageEnable; // 默认值为 False
BOOL IndependentBlendEnable; // 默认值为 False
D3D12_RENDER_TARGET_BLEND_DESC RenderTarget[8];
}
1.AlphaToCoverageEnable:指定为 true,则启用 alpha-to-coverage 功能,这是一种在渲染叶 片或门等纹理时极其有用的一种多重釆样技术。若指定为false,则禁用alpha-to-coverage功能。 另外,要使用此技术还需开启多重采样(即创建后台缓冲区与深度缓冲区时要启用多重采样)。
2.IndependentBlendEnable: Direct3D最多可同时支持8个渲染目标。若此标志被置为true, 即表明可以向每一个渲染目标执行不同的混合操作(不同的混合因子、不同的混合运算以及设 置不同的混合禁用或开启状态等)。如果将此标志设为false,则意味着所有的渲染目标均使用 D3D12_BLEND_DESC: : RenderTarget数组中第一个元素所描述的方式进行混合。多渲染目标技术常用于高级算法,而现在我们只假设每次仅向一个渲染目标进行绘制。
3.RenderTarget:具有 8 个 D3D12_RENDER_TARGET_BLEND_DESC 元素的数组,其中的第 i 个元素描述了如何针对第i个渲染目标进行混合处理。如果IndependentBlendEnable被设 置为false,则所有的渲染目标都将根据RenderTarget [0]的设置进行混合运算。
typedef struct D3D12_RENDER_TARGET_BLEND_DESC
{
BOOL BlendEnable;// 默认值为 False
BOOL LogicOpEnable;// 默认值为 False
D3D12_BLEND SrcBlend;// 默认值为 D3D12_BLEND_ONE
D3D12_BLEND DestBlend;// 默认值为 D3D12_BLEND_ZERO
D3D12_BLEND_OP BlendOp;// 默认值为 D3D12_BLEND_OP_ADD
D3D12_BLEND SrcBlendAlpha;// 默认值为 D3D12_BLEND_ONE
D3D12_BLEND DestBlendAlpha; // 默认值为 D3D12_BLEND_ZERO
D3D12_BLEND_OP BlendOpAlpha; // 默认值为 D3D12_BLEND_OP_ADD
D3D12_LOGIC_OP LogicOp;// 默认值为 D3D12_LOGIC_OP_NOOP
UINT8 RenderTargetWriteMask;// 默认值为 D3D12_COLOR_WRITE_ENABLE_ALL
}
1.BlendEnable:指定为true,则启用常规混合功能;指定为false,则禁用常规混合功能。注意, 不能将BlendEnable与LogicOpEnable同时置为true,只能从常规混合与逻辑运算符混合 两种方式中选择一种。
2.LogicOpEnable:指定为true,则启用逻辑混合运算,反之则反。注意,不能将BlendEnable 和LogicOpEnable同时设置为true,只能从常规混合与逻辑运算混合中选择一种。
3.SrcBlend:枚举类型D3D12_BLEND中的成员之一,用于指定RGB混合中的源混合因子。
4.DestBlend:枚举类型D3D12_BLEND中的成员之一,用于指定RGB混合中的目标混合因子。
5.BlendOp:枚举类型D3D12_BLEND_OP中的成员之一,用于指定RGB混合运算符。
6.SrcBlendAlpha:枚举类型D3D12_BLEND中的f 成员,指定了 alpha混合中的源混合因子。
7.DestBlendAlpha:枚举类型D3D12_BLEND中的一个成员,指定了 alpha混合中的目标混合 因子。
8.BlendOpAlpha:枚举类型D3D12_BLEND_OP中的一个成员,指定了 alpha混合运算符。
9.LogicOp:枚举类型D3D12_LOGIC_OP中的成员之一,指定了源颜色与目标颜色在混合时所 用的逻辑运算符.
10.10.RenderTargetWriteMask:下列标志中一种或多种的组合。
enum D3D12_COLOR_WRITE_ENABLE
{
D3D12_COLOR_WRITE_ENABLE_RED = 1,//允许将数据存储在红色组件中。
D3D12_COLOR_WRITE_ENABLE_GREEN = 2,//允许数据存储在绿色组件中。
D3D12_COLOR_WRITE_ENABLE_BLUE = 4,//允许将数据存储在蓝色组件中。
D3D12_COLOR_WRITE_ENABLE_ALPHA = 8,//允许将数据存储在 alpha 组件中。
D3D12_COLOR_WRITE_ENABLE_ALL = ( ( ( D3D12_COLOR_WRITE_ENABLE_RED | D3D12_COLOR_WRITE_ENABLE_GREEN ) | D3D12_COLOR_WRITE_ENABLE_BLUE ) | D3D12_COLOR_WRITE_ENABLE_ALPHA ) //允许将数据存储在所有组件中。
}
在D3D12_BLEND_DESC结构的 RenderTarget 成员中指定一组D3D12_RENDER_TARGET_BLEND_DESC结构,以描述呈现目标的混合状态;一次最多可将 8 个呈现目标绑定到输出合并阶段。
这些标志控制着混合后的数据可被写入后台缓冲区中的哪些颜色通道。例如,通过指定 D3D12_COLOR_WRITE_ENABLE_ALPHA可以禁止向RGB通道的写操作,而仅写入alpha通道的有关数 据。对于一些高级技术而言,这种灵活性是极其实用的。当混合功能被禁止时,从像素着色器返回的颜 色数据将按没有设置上述写掩码来进行处理(即不对目标像素执行任何操作)。
混合与深度缓冲区
在使用加法/减法/乘法运算进行混合时,会涉及深度测试(depth test)这一问题。我们仅用加法混合来讲解,但其中的思路也同样适用于减法/乘法的混合运算。如果要用加法混合来渲染 一个物体集合S,并希望S中的物体不会互相遮挡,这就意味着我 们只需将这些物体的颜色数据简单地累加即可。为此, 我们不愿在S中的物体之间进行深度测试。若开启深度测试,却 并没有按从后至前的顺序进行绘制,那么,当S中的两个物体存 在遮挡关系,经过深度测试后,靠后的像素片段便会被丢弃,这 意味着该物体的像素颜色将不会被累加至混合求和的结果之中。 在渲染S中的物体时,我们可以通过禁止向深度缓冲区的写操作 来禁用S中物体之间的深度测试。由于深度写入操作已被禁止, S中的物体在进行加法混合时,便不会将深度信息写入深度缓冲 区,因此,S中的物体便不会因深度测试而直接覆盖其后的物体。 注意,我们只是在绘制S (要用加法混合的方式来绘制的一个物 体集合)中的物体时禁用了深度值写入操作,但深度值读取与深 度检测仍然是开启的。这样一来,非混合几何体(比混合几何体 先绘制的物体)仍将遮挡其后的混合几何体。比方说,如果我们 有一个需要在墙后进行加法混合的物体集合,那么这些混合物体 最后是看不到的,因为以非混合方式绘制的实心不透明墙体会挡 住它们。
alpha 通道
源alpha分量能够用于在RGB混合的过程中控制像素的透明度。 而混合方程中所用的源颜色实则来自于像素着色器。
D3D12_GRAPHICS_PIPELINE_STATE_DESC alphaTestedPsoDesc = opaquePsoDesc;
alphaTestedPsoDesc.PS =
{
reinterpret_cast<BYTE*>(mShaders["alphaTestedPS"]->GetBufferPointer()),
mShaders["alphaTestedPS"]->GetBufferSize()
};
alphaTestedPsoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&alphaTestedPsoDesc, IID_PPV_ARGS(&mPSOs["alphaTested"])));
描述光栅器状态。
typedef struct D3D12_RASTERIZER_DESC
{
D3D12_FILL_MODE FillMode;//默认值D3D12_FILL_MODE_SOLID
D3D12_CULL_MODE CullMode;//默认值D3D12_CULL_MODE_BACK
BOOL FrontCounterClockwise;//默认值FALSE
INT DepthBias;// 默认值 0
FLOAT DepthBiasClamp;//默认值 0.0f
FLOAT SlopeScaledDepthBias;//默认值0.0f
BOOL DepthClipEnable;//默认值 TRUE
BOOL MultisampleEnable;//默认值 FALSE
BOOL AntialiasedLineEnable;//默认值 FALSE
UINT ForcedSampleCount;//默认值 0
D3D12_CONSERVATIVE_RASTERIZATION_MODE ConservativeRaster;//默认值D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF
}
1.FillMode:一个D3D12_FILL_MODE类型的值,该值指定呈现时要使用的填充模式。
2.CullMode:一个 D3D12_CULL_MODE类型的值,该值指定不绘制面向指定方向的三角形。
3.FrontCounterClockwise:确定三角形是正面还是背面。 如果此成员为 TRUE,则如果三角形顶点在呈现器目标上逆时针,则三角形将被视为正面;如果顶点顺时针,则被视为朝后。 如果此参数为 FALSE,则相反为 true。
4.DepthBias:给定像素斜率上的标量。有关深度偏差的信息,请参阅深度偏差 。
5.DepthBiasClamp:像素的最大深度偏差。 有关深度偏差的信息,请参阅 深度偏差。
5.SlopeScaledDepthBias:像素的最大深度偏差。 有关深度偏差的信息,请参阅 深度偏差。
6.DepthClipEnable:指定是否启用基于距离的剪裁。硬件始终执行光栅化坐标的 x 和 y 剪裁。 当 DepthClipEnable 设置为 default–TRUE 时,硬件还会剪裁 z 值 (即,硬件) 执行以下算法的最后一步。将 DepthClipEnable 设置为 FALSE 时,硬件会跳过 z 剪裁 (即,上述算法中的最后一步) 。 但是,硬件仍执行“0 < w”剪裁。 禁用 z 剪裁时,可能会导致像素级别的深度排序不正确。 但是,当禁用 z 剪裁时,模具阴影实现将简化。 换句话说,可以避免对超出反向剪裁平面的几何图形进行复杂的特殊情况处理。
7.MultisampleEnable:指定在多重采样抗锯齿 (MSAA) 呈现目标上使用四边形或 alpha 线抗锯齿算法。 设置为 TRUE 以使用四边形线抗锯齿算法,设置为 FALSE 以使用 alpha 行抗锯齿算法。
8.AntialiasedLineEnable:指定是否启用行抗锯齿;仅当进行线条绘制且 MultisampleEnable 为 FALSE 时适用。
9.ForcedSampleCount:类型: UINT。UAV 呈现或光栅化时强制的样本计数。 有效值为 0、1、4、8 和可选 16。 0 表示样本计数不是强制的。
注意 如果要在 ForcedSampleCount 设置为 1 或更大的情况下进行呈现,必须遵循以下准则:
1.不要绑定深度模具视图。
2.禁用深度测试。
3.确保着色器不输出深度。
4.如果有任何呈现目标视图绑定 (D3D12_DESCRIPTOR_HEAP_TYPE_RTV) 且 ForcedSampleCount 大于 1,请确保每个呈现目标只有一个样本。
5.不要以采样频率操作着色器。 因此, ID3D12ShaderReflection:IsSampleFrequencyShader 返回 FALSE。否则,呈现行为未定义。
注意 对于 功能级别 9.1、9.2、9.3 和 10.0,如果将 MultisampleEnable 设置为 FALSE,则即使样本计数大于 1 的呈现目标,运行时也会呈现所有点、线和三角形,而不会抗锯齿。 对于功能级别 10.1 及更高版本, MultisampleEnable 的设置对 MSAA 的点和三角形没有影响,并且仅影响此表中所示的线条呈现算法的选择:
MultisampleEnable 和 AntialiasedLineEnable 成员的设置仅适用于多重采样抗锯齿 (MSAA) 呈现目标 (即,呈现样本计数大于 1) 的目标。 由于 功能级别 行为存在差异,并且只要不执行任何线条绘制或不介意线条呈现为四边形,我们建议每当在 MSAA 呈现目标上呈现时,始终将 MultisampleEnable 设置为 TRUE 。