Reproduce the problem in this project:
https://github.com/adrotter/GDIDirect2DDualRenderer
I am trying to make Direct2D work with our current rendering engine, which is GDI+. I did this by abstracting all the calls to GDI+, and making a concrete class for GDI+ and for Direct2D. One issue that a lot of people seem to have is when you call Clear on the render target with a transparent color, you get completely opaque black background.
How do I clear a Direct2D render target to fully transparent
How to create a transparent bitmap in Direct2D
The answers from the above stack overflow posts suggest I need a WS_EX_LAYERED window, or using DirectComposition, but I am not sure if doing that would work well in WinForms. Besides, they are only talking about making the window transparent and not pixels on a bitmap. The solution I came up with that partially works is if there is a call to Graphics.Clear, and I have yet to start drawing using the render target, then I call Clear on the Drawing.Graphics object, and then start drawing. This will make the background completely transparent if I use Graphics.Clear(Color.Transparent) (fixes the problem people had with the black background).
Here is how that looks like with 100% opacity:
The color ramp on the left is Direct2D rendering, and the color ramp on the right is GDI+. They look similar, but the Direct2D looks darker. It gets worse.
Here's 50% opacity
1% opacity
Now this is why my solution partially works: 0% opacity works great. See here.
Now I don't actually think that the target blending black with transparent is a result of me calling Clear first with the System.Drawing.Graphics object first, because I tested the partial transparency without using my trick (I made no calls to GDI+ graphics at all). I would still get the same results as above for opacities 50 and 1. It seems like calling DrawBitmap using a bitmap with partial transparencies will always blend the partial transparent color with black.
For reference here is how my render target is being made:
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)
Also for reference here is how I turn a System.Drawing.Bitmap into a 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
And here is a simplification of getting my semi transparent bitmaps:
//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
How do I get a white blended partial transparent pixel and not a black one using a GDI+ render target?