如何制作具有透明背景的OpenGL渲染上下文?
渲染上下文通常在背景上有纯色(黑色或其他颜色,请参见下图):
我是想知道是否可以设置一个没有装饰且具有透明背景的窗口,同时允许我在其上渲染 OpenGL 内容。
这会给人一种三角形漂浮在屏幕上的错觉。透明背景应该允许您看到桌面或可能位于其后面的其他应用程序。
能用源码举例说明一下吗?
平台:Windows(仅win32)
Rendering contexts usually have a solid color on the background (black or whatever, see the image below):
I'm wondering if it's possible to setup a window, with no decorations AND with the transparent background, while allowing me to render OpenGL stuff on it.
This would give the illusion that the triangle is floating on the screen. The transparent background should allow you to see the desktop or other applications that might be behind it.
Could you please exemplify with source code?
Platform: Windows (win32 only)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
在花了一些声誉在不成功的赏金上获得关于这个问题的一些帮助之后,我终于意识到我感兴趣的问题有多么复杂。
完成这项任务的少数人不要分享太多。在我的研究过程中,我发现了不同的方法来实现我所寻找的目标。最有趣的之一是 AeroGL,它显示 代码片段使用了迄今为止尚未提及的技术,该技术将图形渲染到设备无关位图 (DIB)。
要永久关闭此线程,下面的源代码实现了该技术。代码本身是对此处提供的应用程序的轻微修改(非常感谢< em>Andrei Sapronov Y.)。
最终结果如下图所示:
该代码已在 Windows XP (32-位)和 Windows 8.1(32 位)。
享受吧!
After spending some reputation on a unsuccessful bounty to get some help on this issue, I finally realized how complex was the problem I was interested in.
The few individuals that have accomplished this task don't share much. During my research I found different ways to achieve what I was looking for. One of the most interesting ones is AeroGL, and it shows snippets of code using a technique that was not mentioned so far, which is rendering the graphics to a device-independent bitmap (DIB).
To close this thread permanently, the source code below implements that technique. The code itself is a slight modification of an application presented here (big thanks to Andrei Sapronov Y.).
The end result can be seen in the image below:
The code has been tested on Windows XP (32-bits) and Windows 8.1 (32-bits).
Enjoy!
由于到目前为止给出的所有答案仅针对 Windows,但肯定也存在使用复合窗口管理器在 X11 上执行此操作的需求,作为参考,我在此处发布了我的示例代码(也可在 https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/x11argb_opengl /x11argb_opengl.c
主要技巧是获取正确的 FBConfig,您需要请求一个 Alpha 通道并测试关联的
XRenderPictFormat
是否存在 Alpha。面具。Since all the answers given so far target Windows only, but there's surely also a demand doing this on X11 with a composited window manager, for reference I post my example code here (also to be found at https://github.com/datenwolf/codesamples/blob/master/samples/OpenGL/x11argb_opengl/x11argb_opengl.c
The main trick is getting the right FBConfig. You need to ask for a alpha channel and test the associated
XRenderPictFormat
for the presence of an alpha mask.我知道这在 Windows 7 中是可能的,但不确定早期版本是否如此。
要摆脱窗口边框,您需要从窗口中删除
WS_OVERLAPPEDWINDOW
样式并添加WS_POPUP
样式:要使 OpenGL 窗口的背景透明,您需要使用
DwmEnableBlurBehindWindow
函数:在调用
glClearColor
时,您还需要为alpha值指定0。另外,在创建 OpenGL 上下文时,请确保分配 Alpha 通道。
现在你的背景应该是完全透明的。如果保留窗口装饰,则背景将使用 Aero 模糊外观,并且您可以使用
glClearColor
中的 alpha 值调整透明度级别。I know this is possible with Windows 7, not sure about earlier versions.
To get rid of the window border you need to remove the
WS_OVERLAPPEDWINDOW
style from the window and add theWS_POPUP
style:To make the background of the OpenGL window transparent, you will need to use the
DwmEnableBlurBehindWindow
function:You will also need to specify 0 for the alpha value when calling
glClearColor
.Also, when creating your OpenGL context, make sure you allocate an alpha channel.
Now your background should be fully transparent. If you keep the window decorations, then the background will use the Aero blur look and you can adjust the level of transparency using the alpha value in
glClearColor
.这是一个老问题,但由于较新版本的 Windows 已经对 opengl 进行了合成和支持,正如 datenwolf 所暗示的那样,我们可以使用一些特殊的手段来完成此任务。尽管对于 DirectX 来说这也是微不足道的(想想看……)微软确实向 opengl 上下文添加了合成提示。是的,反垄断恐惧!
因此,我们可以让合成引擎了解如何使用 opengl 上下文,而不是执行低效的复制到物理内存操作。
因此,您必须创建一个带有指定 Alpha 通道的像素格式的 opengl 上下文,并且它应该使用合成(第 82 行)。然后,您使用 DwmApi.h 例程启用指定了完全无效区域的模糊窗口(第 179 行),这不会模糊任何内容并使窗口保持透明。 (您需要在窗口类上指定黑色+透明画笔!奇怪!)然后,您实际上只需使用 opengl,就像您习惯使用它一样。在事件循环中,只要有机会,您就可以绘制和交换缓冲区(第 201 行),并记住启用 GL_BLEND! :)
请查看/fork https://gist.github.com/3644466 或仅查看以下基于以下代码片段OP自己用这种技术给出的答案(你可以把它放在一个空项目中):
This is an old question, but since newer versions of Windows have compositing and support, as datenwolf hints, for opengl, we can use some of that special sauce for accomplishing this. Although it is also trivial with DirectX (go figure...) Microsoft did add compositing hints to opengl contexts. Yay anti-trust fears!
So instead of an inefficient copy-to-physical-memory action, we can have the compositing engine just understand how to make use of the opengl context.
So, you have to create an opengl context with a pixelformat that specifies an alpha channel and that it should use composition (line 82). Then, you use the DwmApi.h routines to enable a blurred window (line 179) with a completely invalid region specified, which will blur nothing and leave the window transparent. (You need to specify a black+transparent brush on the window class! Oddly!) Then, you actually just use opengl as you are used to using it. In the event loop, every chance you get, you can just draw and swap buffers (line 201) and remember to enable GL_BLEND! :)
Please review/fork https://gist.github.com/3644466 or just view the following code snippet based off of the OP's own answer with this technique instead (you can just plop this in an empty project):
如果允许 OpenGL 窗口分层,这将非常容易。但他们不是,所以你必须去寻找别的东西。
您可以做的是创建一个分层窗口(WS_EX_LAYERED + SetLayeredWindowAttributes() - 如果您不知道它们,请 Google 一下)来处理透明度,并创建一个用于渲染的隐藏 OpenGL 窗口。将 OpenGL 场景渲染到离屏缓冲区,读回并与分层窗口共享,然后通过 bitblt(GDI 函数)将其传输到分层窗口。
对于非常复杂的东西来说这可能太慢了,但是会给你你所要求的效果,并且可以在 Windows 2000 及更高版本上工作。
编辑:当涉及到创建实际的离屏缓冲区时,帧缓冲区对象(FBO)可能是您最好的选择。你可以直接在隐藏的 OpenGL 窗口上绘图,不过我想我记得有人发帖说由于像素所有权而遇到了麻烦 - 建议使用 FBO。您还可以使用像素缓冲区(pbuffers),但这些有点过时(标记为“遗留”),并且 FBO 被认为是实现此目的的现代方法。 FBO 应该为您提供硬件加速(如果支持),并且本身不会限制您使用特定的 OpenGL 版本。您需要一个 OpenGL 上下文才能使用它,因此您必须创建隐藏的 OpenGL 窗口并从那里设置 FBO。
以下是一些有关 FBO 的资源:
维基百科
FBO
Gamedev 文章
指南(适用于 Mac ,但可能会有所帮助)
This would be very easy if OpenGL windows were allowed to be layered. But they are not, so you'll have to go for something else.
What you could do is to create a layered window (WS_EX_LAYERED + SetLayeredWindowAttributes() - Google 'em if you don't know them) to handle the transparency, and a hidden OpenGL window for the rendering. Render the OpenGL scene to an off-screen buffer, read it back and share it with the layered window, then bitblt (GDI function) it to the layered window.
This might be too slow for very complex stuff, but will give you the effect you are asking for, and work on Windows 2000 and above.
EDIT: When it comes to creating the actual off-screen buffer, framebuffer objects (FBOs) are probably your best bet. You could just draw on the hidden OpenGL window, though I think I recall someone posting about running into troubles with that, because of pixel ownership - FBOs are recommended. You could also use pixel buffers (pbuffers), but these are kind of outdated (stamped "legacy"), and FBOs are considered the modern way to do this. FBOs should give you hardware acceleration (if supported), and won't itself limit you to a specific OpenGL version. You'll need an OpenGL context to use it, so you'll have to create that hidden OpenGL window and set up the FBO from there.
Here are some resources on FBOs:
Wikipedia
FBO
Gamedev article
Guide (for mac, but might be helpful)
我知道这已经很旧了,但我试图将 Xlib 解决方案移植到 Gtk+。经过大量研究,我终于成功了,所以我真的很想在这里分享给有需要的人。
使用 gcc main.c -o main `pkg-config --libs --cflags gtk+-2.0 gtkglext-1.0` 编译。在 Ubuntu 18.04 上测试(除了 gtk,您还需要安装
libgtkglext1-dev
)。编辑
我将渲染代码从简单的
glClear
更改为矩形。该代码是此问题以及这个问题。
I know this is old, but I was trying to port the Xlib solution to Gtk+. After a lot of study I finally made it so I really want to share it here for anyone in need.
Compiled with
gcc main.c -o main `pkg-config --libs --cflags gtk+-2.0 gtkglext-1.0`
. Tested on Ubuntu 18.04 (in addition to gtk, you'll need to installlibgtkglext1-dev
).EDIT
I changed the rendering code from simply a
glClear
to a rectangle.The code is a modified version from this question and also this question.
您可以将 3D 场景渲染到 pbuffer 并使用颜色键将其传输到屏幕。
You can render the 3d scene to a pbuffer and blit it to screen using a color key.
ClanLib 游戏 SDK 可以做到这一点。
如果您只需要静态透明边框,请使用以下技术:
创建 5 个窗口
AAAAA
B###C
B###C
DDDDD
A、B、C、D 是分层窗口
“#”是主窗口。
请参阅底部的图像 - http://clanlib.org/wiki/ClanLib_2.2.9_Release_Notes
The ClanLib game SDK does this.
If you only require a static transparent border use the following technique:
Creates 5 windows
AAAAA
B###C
B###C
DDDDD
A,B,C,D are layered windows
"#" is the main window.
See the images at the bottom of - http://clanlib.org/wiki/ClanLib_2.2.9_Release_Notes