GDI 渲染到 direct2D ID2D1BitmapRenderTarget 始终是透明的

发布于 2024-10-10 10:57:30 字数 1967 浏览 9 评论 0原文

我想将我的电影渲染软件从 DirectDraw 移植到 Direct2D。由于兼容性问题,GDI 渲染需要在图像之上完成。为了优化性能,我想实现某种后备缓冲机制,但 alpha 通道信息似乎存在问题,所有 GDI 绘图都显得透明

我为窗口句柄创建一个 ID2D1HwndRenderTarget ,并创建一个用于将图像复制到的 ID2D1Bitmap 。位图的像素格式为DXGI_FORMAT_B8G8R8A8_UNORM,Alpha模式为D2D1_ALPHA_MODE_IGNORE。 HwdRenderTarget 是 GDI 兼容的,所以我的渲染函数看起来像这样:

HwdRenderTarget.BeginDraw;
HwdRenderTarget.DrawBitMap(myBitMap);
HwdRenderTarget.GetDC(dc);

... do GDI drawing here ...

HwdRenderTarget.ReleaseDC();
HwdRenderTarget.EndDraw;

这个版本工作得很好:GDI 对象用纯色绘制,DrawTextEx-Text 具有透明背景。

为了优化性能,我想在“后备缓冲区”中进行 GDI 绘图,因此只有在发生变化时才需要执行此操作。 否则我只能渲染缓存的位图。位图是空的且透明的,因此只有绘制的对象应该是可见的。

因此,我创建了一个 CompatibleRenderTarget ID2D1BitmapRenderTarget,alpha 模式为 D2D1_ALPHA_MODE_PREMULTIPLIED

 HwdRenderTarget.CreateCompatibleRenderTarget(nil, nil, nil, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE, CompatibleRenderTarget);

现在我在 CompatibleRenderTarget 中进行 GDI 渲染:

CompatibleRenderTarget.BeginDraw;
if Supports(CompatibleRenderTarget, ID2D1GdiInteropRenderTarget, GdiInteropRenderTarget) then
begin
  GdiInteropRenderTarget.GetDC(D2D1_DC_INITIALIZE_MODE_CLEAR, dc);

  ... do GDI drawing here ...

  GdiInteropRenderTarget.ReleaseDC(fDstSize);
end;
GdiInteropRenderTarget := nil;
CompatibleRenderTarget.EndDraw;
CompatibleRenderTarget.GetBitmap(BackBuffer); // save the bitmap for drawing

现在我的渲染函数如下所示:

HwdRenderTarget.BeginDraw;
HwdRenderTarget.DrawBitMap(myBitMap);
HwdRenderTarget.DrawBitmap(BackBuffer);
HwdRenderTarget.EndDraw;

现在的问题是, 所有 GDI 绘图在某种程度上都是透明的,并且透明度取决于底层图像像素的值。深色文本在深色图像背景上显示为黑色,但在白色背景上变为白色。但是 GDI 中不使用 Alpha 通道,并且 myBitmap 也没有 Alpha 信息。

那么alpha信息从哪里来呢?有人有主意吗?提前致谢!

顺便说一句,在 CompatibleRenderTarget 上使用 Direct2D 绘图也可以正常工作。

I want to port my movie rendering software from DirectDraw to Direct2D. Because of compatibility issues, GDI rendering needs to be done on top of the image. To optimize performance I want to implement some kind of backbuffer mechanism, but there seems to be a problem with the alpha channel information, all GDI drawing appears somehow transparent.

I create a ID2D1HwndRenderTarget for my window handle and and a ID2D1Bitmap to copy the images to. The pixelformat of the bitmap is DXGI_FORMAT_B8G8R8A8_UNORM, the alpha mode is D2D1_ALPHA_MODE_IGNORE. The HwdRenderTarget is GDI compatible, so my render function looks somehow like this:

HwdRenderTarget.BeginDraw;
HwdRenderTarget.DrawBitMap(myBitMap);
HwdRenderTarget.GetDC(dc);

... do GDI drawing here ...

HwdRenderTarget.ReleaseDC();
HwdRenderTarget.EndDraw;

This version works perfectly fine: the GDI objects draw with solid colors, DrawTextEx-Text has a transparent background.

To optimize performance, I want to do the GDI drawing in a "backbuffer", so it only needs to be done when something changes.
Otherwise I just can render the cached bitmap. The bitmap is empty and transparent, so only the objects drawn should be visible.

So I create a CompatibleRenderTarget ID2D1BitmapRenderTarget, alpha mode is D2D1_ALPHA_MODE_PREMULTIPLIED:

 HwdRenderTarget.CreateCompatibleRenderTarget(nil, nil, nil, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE, CompatibleRenderTarget);

Now I do the GDI rendering in the CompatibleRenderTarget:

CompatibleRenderTarget.BeginDraw;
if Supports(CompatibleRenderTarget, ID2D1GdiInteropRenderTarget, GdiInteropRenderTarget) then
begin
  GdiInteropRenderTarget.GetDC(D2D1_DC_INITIALIZE_MODE_CLEAR, dc);

  ... do GDI drawing here ...

  GdiInteropRenderTarget.ReleaseDC(fDstSize);
end;
GdiInteropRenderTarget := nil;
CompatibleRenderTarget.EndDraw;
CompatibleRenderTarget.GetBitmap(BackBuffer); // save the bitmap for drawing

and my render function now looks like this:

HwdRenderTarget.BeginDraw;
HwdRenderTarget.DrawBitMap(myBitMap);
HwdRenderTarget.DrawBitmap(BackBuffer);
HwdRenderTarget.EndDraw;

The problem now is, that all GDI drawing is somehow transparent and the degree of transparency depends on the values of the underlying image pixels. Dark text appears dark on a dark image background but becomes white on a white background. But alpha channel is not used in GDI and myBitmap also has no alpha information.

So where does the alpha information come from? Anyone has an idea? Thanks in advance!

Btw, using Direct2D drawing on the CompatibleRenderTarget also works fine.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

谁与争疯 2024-10-17 10:57:30

我也有同样的问题。以下内容对我有用(您需要使用 D2D1_ALPHA_MODE_IGNORE 而不是 D2D1_ALPHA_MODE_PREMULTIPLIED 创建渲染目标)。

ID2D1HwndRenderTarget* pRenderTarget; // render target created sometime earlier

D2D1_PIXEL_FORMAT pixelFormat = D2D1::PixelFormat(
    DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE);

ID2D1BitmapRenderTarget* pOffscreenRT = NULL;
pRenderTarget->CreateCompatibleRenderTarget(NULL, NULL, &pixelFormat,
    D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE, &pOffscreenRT);

I had the same problem. The following worked for me (you need to create the render target using the D2D1_ALPHA_MODE_IGNORE, not D2D1_ALPHA_MODE_PREMULTIPLIED).

ID2D1HwndRenderTarget* pRenderTarget; // render target created sometime earlier

D2D1_PIXEL_FORMAT pixelFormat = D2D1::PixelFormat(
    DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE);

ID2D1BitmapRenderTarget* pOffscreenRT = NULL;
pRenderTarget->CreateCompatibleRenderTarget(NULL, NULL, &pixelFormat,
    D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE, &pOffscreenRT);
习ぎ惯性依靠 2024-10-17 10:57:30

使用 GDI 渲染有一个肮脏的小秘密:它总是会破坏 Alpha 通道。您用它绘制的任何内容都会将该区域的 alpha 值设置为零。我怀疑这是因为它从未被设计用于 Alpha 通道或任何类型的合成。它被设计为直接渲染到屏幕和打印机,其中不存在 Alpha 通道。

There's a dirty little secret about rendering with GDI: It will always clobber the alpha channel. Anything you draw with it will set the alpha values to zero in that area. I suspect it's because it was never designed to work with an alpha channel or any type of compositing. It was designed to render directly to the screen and to printers, where alpha channels don't exist.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文