介绍
当两张图片重叠的时候,可以一张完全盖住另外一张,也可以实现两张图片融合的结果。本文将对图片融合展开介绍。
融合的公式如下
C
=
C
s
r
c
⊕
F
s
r
c
1
Θ
C
d
s
t
⊕
F
d
s
t
1
\ C = C_{src}\oplus F_{src1} \Theta C_{dst} \oplus F_{dst1}
C=Csrc⊕Fsrc1ΘCdst⊕Fdst1
A
=
A
s
r
c
⊕
F
s
r
c
2
Θ
A
d
s
t
⊕
F
d
s
t
2
\ A = A_{src}\oplus F_{src2} \Theta A_{dst} \oplus F_{dst2}
A=Asrc⊕Fsrc2ΘAdst⊕Fdst2
其中 C 代表颜色(color);A 代表透明度(transparent)。
C
s
r
c
\ C_{src}
Csrc 代表从像素着色器输出的像素,对应本文的狗像素;
F
s
r
c
1
\ F_{src1}
Fsrc1 代表各 rgb 的比重,可通过程序设置;
C
s
r
c
⊕
F
s
r
c
1
\ C_{src}\oplus F_{src1}
Csrc⊕Fsrc1,表示{
R
s
r
c
∗
F
r
s
r
c
1
,
G
s
r
c
∗
F
g
s
r
c
1
,
B
s
r
c
∗
F
b
s
r
c
1
\ R_{src}*F_{r_{src1}},G_{src}*F_{g_{src1}},B_{src}*F_{b_{src1}}
Rsrc∗Frsrc1,Gsrc∗Fgsrc1,Bsrc∗Fbsrc1}。
C
d
s
t
\ C_{dst}
Cdst 代表已经存在后备缓冲区的数据,对应本文的背景颜色。
Θ
\ \Theta
Θ 表示
C
s
r
c
⊕
F
s
r
c
1
\ C_{src}\oplus F_{src1}
Csrc⊕Fsrc1 和
C
d
s
t
⊕
F
d
s
t
1
\ C_{dst} \oplus F_{dst1}
Cdst⊕Fdst1 的结果之间怎么融合,常用的有 add,就是将 rgb 分别相加。
最终效果
没开融合时的现象
开了融合后的现象
代码
OMSetBlendState
设置输出的融合方式
主要增加的代码
ID3D11BlendState* blendState;
D3D11_BLEND_DESC blendDesc = {};
blendDesc.AlphaToCoverageEnable = FALSE;
blendDesc.IndependentBlendEnable = FALSE;
blendDesc.RenderTarget->BlendEnable = TRUE; // 是否开启混合
blendDesc.RenderTarget->SrcBlend = D3D11_BLEND_SRC_ALPHA; // 将源图的 alpha 作为 src rgb 的混合因子
blendDesc.RenderTarget->DestBlend = D3D11_BLEND_INV_SRC_ALPHA; // 将源图的 1-alpha 作为 dst rgb 的混合因子
blendDesc.RenderTarget->BlendOp = D3D11_BLEND_OP_ADD; // 进行相加操作
blendDesc.RenderTarget->SrcBlendAlpha = D3D11_BLEND_ONE; //
blendDesc.RenderTarget->DestBlendAlpha = D3D11_BLEND_ONE;
blendDesc.RenderTarget->BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget->RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; // 可以写入的位置
m_pDevice->CreateBlendState(&blendDesc, &blendState);
const FLOAT BlendFactor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
m_pContext->OMSetBlendState(blendState, BlendFactor, 0xffffffff);
BlendEnable 表示是否开启融合;SrcBlend 对应公式里面的 F s r c 1 \ F_{src1} Fsrc1 ,DestBlend 对应公式里面的 F d s t 1 \ F_{dst1} Fdst1 , BlendOp 对应第一个公式的 Θ \ \Theta Θ。SrcBlendAlpha 对应公式里面的 F s r c 2 \ F_{src2} Fsrc2 ,DestBlendAlpha 对应公式里面的 F d s t 2 \ F_{dst2} Fdst2,BlendOpAlpha 对应第二个公式的 Θ \ \Theta Θ。RenderTargetWriteMask 表示哪些颜色通道可以写入。
具体代码
rt slot
1, // buffer 数量 (start slot ~ start slot + buffer number
&verticesBuffer,// 顶点缓存
&strider, // 每组数据的字节数
&offset); // 偏移量
DirectX::XMUINT3 index[] = {
{0, 1, 2},
{0, 2, 3}};
D3D11_BUFFER_DESC indexDesc = {};
indexDesc.ByteWidth = sizeof(index) * 2; // 字节数
// 将 usage 设为 D3D11_USAGE_IMMUTABLE D3D11_USAGE_DEFAULT 可行
indexDesc.Usage = D3D11_USAGE_IMMUTABLE; // 资源的使用,gpu和cpu 的读写权限
indexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; // 标识如何将资源绑定到 pipeline
indexDesc.CPUAccessFlags = 0; // CPU 的读写权限
indexDesc.MiscFlags = 0;
indexDesc.StructureByteStride = 0;
resourceData.pSysMem = index;
resourceData.SysMemPitch = 0;
resourceData.SysMemSlicePitch = 0;
ID3D11Buffer* indexBuffer = NULL;
m_pDevice->CreateBuffer(&indexDesc, &resourceData, &indexBuffer);
// 设置所引缓存
m_pContext->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R32_UINT, 0);
// 输入布局
m_pContext->IASetInputLayout(m_inputLayout);
// 图元拓扑结构
m_pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
/************************************* 顶点着色器阶段 **************************************/
m_pContext->VSSetShader(m_pVertexShader, nullptr, 0);
/************************************* 像素着色器阶段 **************************************/
m_pContext->PSSetShader(m_pPixelShader, nullptr, 0);
ID3D11Resource* inputResource = NULL;
ID3D11ShaderResourceView* shaderResourceView = NULL;
std::wstring path = L"res\\image\\dog2.png";
CreateWICTextureFromFile(m_pDevice,
path.c_str(),
&inputResource,
&shaderResourceView);
m_pContext->PSSetShaderResources(0, 1, &shaderResourceView);
ID3D11SamplerState* sampler;
D3D11_SAMPLER_DESC sampleDesc = {};
sampleDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampleDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; // 平铺整数个
sampleDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampleDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampleDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampleDesc.MinLOD = 0;
sampleDesc.MaxLOD = D3D11_FLOAT32_MAX;
m_pDevice->CreateSamplerState(&sampleDesc, &sampler);
m_pContext->PSSetSamplers(0, 1, &sampler);
/************************************* 输出阶段 **************************************/
// 设置渲染目标
m_pContext->OMSetRenderTargets(1, &m_pRenderTargetView, NULL);
ID3D11BlendState* blendState;
D3D11_BLEND_DESC blendDesc = {};
blendDesc.AlphaToCoverageEnable = FALSE;
blendDesc.IndependentBlendEnable = FALSE;
blendDesc.RenderTarget->BlendEnable = TRUE; // 是否开启混合
blendDesc.RenderTarget->SrcBlend = D3D11_BLEND_SRC_ALPHA; // 将源图的 alpha 作为 src rgb 的混合因子
blendDesc.RenderTarget->DestBlend = D3D11_BLEND_INV_SRC_ALPHA; // 将源图的 1-alpha 作为 dst rgb 的混合因子
blendDesc.RenderTarget->BlendOp = D3D11_BLEND_OP_ADD; // 进行相加操作
blendDesc.RenderTarget->SrcBlendAlpha = D3D11_BLEND_ONE; //
blendDesc.RenderTarget->DestBlendAlpha = D3D11_BLEND_ONE;
blendDesc.RenderTarget->BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget->RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; // 可以写入的位置
m_pDevice->CreateBlendState(&blendDesc, &blendState);
const FLOAT BlendFactor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
m_pContext->OMSetBlendState(blendState, BlendFactor, 0xffffffff);
// 设置视口
D3D11_VIEWPORT viewPort = {};
viewPort.TopLeftX = 0;
viewPort.TopLeftY = 0;
viewPort.Width = 800;
viewPort.Height = 600;
viewPort.MinDepth = 0.0f;
viewPort.MaxDepth = 1.0f;
m_pContext->RSSetViewports(1, &viewPort);
// 开始绘制
m_pContext->DrawIndexed(6, 0, 0);
}
参考文献
https://www.cnblogs.com/X-Jun/p/9346640.html