首页 > 解决方案 > Direct2D 与 GDI+ 渲染目标混合透明为黑色

问题描述

重现此项目中的问题:

https://github.com/adrotter/GDIDirect2DDualRenderer


我正在尝试使 Direct2D 与我们当前的渲染引擎 GDI+ 一起工作。为此,我将所有对 GDI+ 的调用抽象化,并为 GDI+ 和 Direct2D 创建了一个具体的类。很多人似乎遇到的一个问题是,当您在具有透明颜色的渲染目标上调用 Clear 时,您会得到完全不透明的黑色背景。

如何将 Direct2D 渲染目标清除为完全透明

如何在 Direct2D 中创建透明位图

来自上述堆栈溢出帖子的答案表明我需要一个 WS_EX_LAYERED 窗口,或者使用 DirectComposition,但我不确定这样做在 WinForms 中是否有效。此外,他们只是在谈论使窗口透明而不是位图上的像素。我想出的部分可行的解决方案是,如果调用了 Graphics.Clear,但我还没有开始使用渲染目标进行绘制,那么我在 Drawing.Graphics 对象上调用 Clear,然后开始绘制。如果我使用 Graphics.Clear(Color.Transparent),这将使背景完全透明(解决人们对黑色背景的问题)。

这是 100% 不透明度时的样子:

在此处输入图像描述

左边的色带是 Direct2D 渲染,右边的色带是 GDI+。它们看起来相似,但 Direct2D 看起来更暗。它变得更糟。

这是 50% 的不透明度

在此处输入图像描述

1% 不透明度

在此处输入图像描述

现在这就是我的解决方案部分有效的原因:0% 的不透明度效果很好。看这里。

在此处输入图像描述

现在我实际上并不认为将黑色与透明混合的目标是我首先使用 System.Drawing.Graphics 对象调用 Clear 的结果,因为我在没有使用我的技巧的情况下测试了部分透明度(我没有调用 GDI+ 图形完全)。对于不透明度 50 和 1,我仍然会得到与上面相同的结果。似乎使用具有部分透明度的位图调用 DrawBitmap 将始终将部分透明颜色与黑色混合。

以下是我的渲染目标的制作方式供参考:

 Dim targetProperties As New RenderTargetProperties
      targetProperties.Type = RenderTargetType.Default
      targetProperties.PixelFormat = New Direct2D1.PixelFormat(Format.B8G8R8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied)
      targetProperties.Usage = RenderTargetUsage.GdiCompatible
      Dim factory = New Direct2D1.Factory()
      _target = New DeviceContextRenderTarget(factory, targetProperties)
      _target.BindDeviceContext(_graphics.GetHdc(), rec)

这里还可以参考我如何将 System.Drawing.Bitmap 转换为 Direct2D1Bitmap:

 Private Function GetDirect2DBitmap(bmp As System.Drawing.Bitmap) As SharpDX.Direct2D1.Bitmap
    Dim bmpData As System.Drawing.Imaging.BitmapData = bmp.LockBits(
            New System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height),
            System.Drawing.Imaging.ImageLockMode.ReadOnly,
            System.Drawing.Imaging.PixelFormat.Format32bppPArgb)
    Dim stream As New SharpDX.DataStream(bmpData.Scan0, bmpData.Stride * bmpData.Height, True, False)
    Dim pFormat As New SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm, Direct2D1.AlphaMode.Premultiplied)
    Dim bmpProps As New SharpDX.Direct2D1.BitmapProperties(pFormat)

    Dim result As New SharpDX.Direct2D1.Bitmap(
            _targets(_selectedTargetIdx),
            New SharpDX.Size2(bmp.Width, bmp.Height),
            stream,
            bmpData.Stride,
            bmpProps)

    bmp.UnlockBits(bmpData)

    stream.Dispose()



    Return result
End Function

这是获取我的半透明位图的简化:

//using C# style comments so this looks prettier

//Make empty bitmap to draw on
dim canvasBMP = new System.Drawing.Bitmap(100,100)

//Make the bitmap that has partial transparent pixels
dim partialTransparentBMP as System.Drawing.Bitmap = GetSemiTransparentBMP(100,100)

Using g as System.Drawing.Graphics = Graphics.FromImage(canvasBMP)
    g.Clear(Color.White)
    dim d2dTarget = MakeRenderTarget(g, g.VisibleClipBounds)
    d2dTarget.BeginDraw()
    d2dTarget.DrawBitmap(GetDirect2DBitmap(partialTransparentBMP), GetDirect2DRect(...), 1.0F, BitmapInterpolationMode.Linear)
    d2dTarget.EndDraw()
End Using

如何使用 GDI+ 渲染目标获得白色混合的部分透明像素而不是黑色像素?

标签: winformsgdi+sharpdxdirect2d

解决方案


推荐阅读