DirectX 图像纹理四边形在透明处显示底层控件颜色

DirectX Image texture quad displays underlying controls color where it is transparent

我正在尝试在纹理上绘制纹理,如下图所示。

黄圈图片:

绿圈图片:

如上面的企鹅图片所示,我正在尝试将另一张图片渲染为绿色和黄色圆圈所示的纹理。显示紫色的图像是透明的。紫色是绘制纹理的底层控件的颜色。

渲染顺序为: 1.渲染企鹅 2.渲染绿色圆圈 3.渲染黄色圆圈 4. 渲染绿色圆圈

现在我不确定为什么我会看到 green/yellow 圆形图像是紫色的?

通过测试我发现,如果我不设置混合因子并使用不同的图像作为具有 alpha 值的叠加图像,那么它可以正常工作。因此,当我使用 alpha 值为 0 的图像时,似乎有些事情发生了。

几个星期以来,我一直试图找出这背后的原因,但无法弄清楚它的原因。

有什么建议或可以指导我正确的方向吗?

注意:将 Directx11 与 ShapDx 一起使用

P.S。我也在另一个论坛上发布了这个问题 here 但到目前为止没有运气。

编辑: 在渲染作为背景的企鹅图像后启用混合状态的代码

        var renderTargetDesc = new RenderTargetBlendDescription();
        renderTargetDesc.IsBlendEnabled = true;
        renderTargetDesc.SourceBlend = BlendOption.SourceAlpha;
        renderTargetDesc.DestinationBlend = BlendOption.InverseSourceAlpha;
        renderTargetDesc.BlendOperation = BlendOperation.Add;
        renderTargetDesc.SourceAlphaBlend = BlendOption.One;
        renderTargetDesc.DestinationAlphaBlend = BlendOption.Zero;
        renderTargetDesc.AlphaBlendOperation = BlendOperation.Add;
        renderTargetDesc.RenderTargetWriteMask = ColorWriteMaskFlags.All;

        BlendStateDescription desc = new BlendStateDescription();
        desc.AlphaToCoverageEnable = false;
        desc.IndependentBlendEnable = false;

        if (m_blendStateEnabled == null)
        {
            m_blendStateEnabled = new BlendState(m_Dx11Device, desc);
        }

        desc.RenderTarget[0] = renderTargetDesc;
        desc.RenderTarget[1] = renderTargetDesc;

        m_Dx11Device.ImmediateContext.OutputMerger.BlendState = m_blendStateEnabled;
        m_Dx11Device.ImmediateContext.OutputMerger.BlendFactor = new Color4(0, 0, 0, 0);
        m_Dx11Device.ImmediateContext.OutputMerger.BlendSampleMask = 0x0F;

P.S。编辑: 我一直在尝试通过缩小范围来尝试不同的方法,我可以得出混合工作的结论,但不是预期的那样,但已经设法缩小了范围。

尝试在画中画上渲染图像时:

首先,我把所有四边形的图都分开了class。使用这个 class 我可以通过调用几个函数来绘制尽可能多的对象,包括在绘制调用中设置以下内容:

DxDevice.ImmediateContext.InputAssembler.InputLayout = m_shaderData.InputLayoutConfig;
DxDevice.ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleStrip;

SetVertexBuffer();

DxDevice.ImmediateContext.VertexShader.Set(m_shaderData.VertexShaderConfig);
DxDevice.ImmediateContext.PixelShader.Set(m_shaderData.PixelShaderConfig);

DxDevice.ImmediateContext.Draw(4, 0);

现在,通过广泛的测试和尝试,我发现:

  1. 我有一个绘制背景的四边形绘图对象和一个单独的绘制旗帜 png 的四边形对象。使用这种方式,png 将显示实际的控件颜色。

现在,如果我启用 AlphaBlending,我得到的只是填充标志 png 四边形的灰色。同样为此,我尝试更新渲染,当我对纹理进行采样时返回 rgb 颜色: ShaderTexture.Sample(采样器,input.TextureUV); 返回的颜色是黑色:r=1, g=1, b= 1, a= 1

  1. 如果我重复使用我用来绘制背景图像的同一个四边形对象,然后绘制旗帜 png,那么我的背景图像将绘制在代表旗帜 png 的四边形内的旗帜 png 下方,我的背景图像是在更大的四边形上没有四边形。

现在从上面(在第 2 点中找到。);如果我使用新的四边形绘制,混合似乎不起作用。

知道为什么会发生这种情况吗?

这是因为当你渲染你的圆圈时,像素alpha也会写入,如果你的最终合成图像必须是不透明的,你可以使用RGBX8表面,或者在混合状态中屏蔽掉alpha通道写入colormask ,并确保将其清除为白色:

renderTargetDesc.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL & ~D3D11_COLOR_WRITE_ENABLE_ALPHA;

好的,我让它工作了。

我执行了以下步骤:

        var renderTargetDesc = new RenderTargetBlendDescription();
        renderTargetDesc.IsBlendEnabled = true;
        renderTargetDesc.SourceBlend = BlendOption.SourceAlpha;
        renderTargetDesc.DestinationBlend = BlendOption.InverseSourceAlpha;
        renderTargetDesc.BlendOperation = BlendOperation.Add;
        renderTargetDesc.SourceAlphaBlend = BlendOption.Zero;
        renderTargetDesc.DestinationAlphaBlend = BlendOption.One;
        renderTargetDesc.AlphaBlendOperation = BlendOperation.Add;
        renderTargetDesc.RenderTargetWriteMask = ColorWriteMaskFlags.All;

        BlendStateDescription desc = new BlendStateDescription();
        desc.AlphaToCoverageEnable = false;
        desc.IndependentBlendEnable = false;
        desc.RenderTarget[0] = renderTargetDesc;

        var blendStateEnabled = new BlendState(DxDevice, desc);

        var blendFactor = new Color4(0, 0, 0, 0);
        var iSampleMask = ~0;
        DxDevice.ImmediateContext.OutputMerger.SetBlendState(blendStateEnabled, blendFactor, iSampleMask);

        UpdateShaderResource();

        DxDevice.ImmediateContext.InputAssembler.InputLayout = m_shaderData.InputLayoutConfig;
        DxDevice.ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleStrip;

        SetVertexBuffer();

        DxDevice.ImmediateContext.VertexShader.Set(m_shaderData.VertexShaderConfig);
        DxDevice.ImmediateContext.PixelShader.Set(m_shaderData.PixelShaderConfig);

        DxDevice.ImmediateContext.OutputMerger.BlendState = null;