如何使用OpenGL在Windows上的同一应用程序中的两个单独的3D窗口中进行绘制

How can I draw inside two separate 3D windows within the same application on Windows using OpenGL?

本文关键字:单独 两个 3D 窗口 绘制 Windows 何使用 应用程序 OpenGL      更新时间:2023-10-16

我正在Windows上的C++第三方程序中实现一个插件。

第三方程序有一个窗口,使用 OpenGL 显示 3D 图形。但是,我需要该插件来创建另一个窗口,该窗口也使用 OpenGL 显示 3D 图形。

我是否需要为我的窗口创建新的 OpenGL 渲染上下文,或者是否有某种方法可以"重用"第三方程序使用的 OpenGL 渲染上下文?

假设我必须创建一个新的 OpenGL 渲染上下文并尝试以下操作:

// create a rendering context  
hglrc = wglCreateContext (hdc); 
// make it the calling thread's current rendering context 
wglMakeCurrent (hdc, hglrc);

但是,最后一个函数失败了。阅读wglMakeCurrent的文档,我注意到

一个线程可以有一个当前呈现上下文。通过多线程处理,一个进程可以具有多个呈现上下文。

这是否意味着我的窗口需要在与第三方程序不同的线程中运行?

你没有发布由wglMakeCurrent((生成的错误代码,所以我不会猜测原因。但是,这不是绑定本身。句子"一个线程可以有一个当前渲染上下文"意味着,新上下文将"替换"旧上下文并成为当前上下文。我不知道您为什么要尝试将两个上下文设置为当前(或运行另一个线程(,但这不是要走的路。除非绝对必要,否则避免在渲染中使用多线程。所以,回答你的问题:

是的,您可以"重用"OpenGL渲染上下文。

你可能会问,为什么?渲染上下文是为特定设备上下文 (HDC( 创建的,这是每个窗口 (HWND( 的专有属性!这怎么可能?!

好吧,由于功能原型,这似乎是不可能的:

   HWND my_window = CreateWindow(...(;    HDC my_dc = GetDC(my_new_window(;    设置"my_dc"的像素格式...    HGLRC my_rc = wglCreateContext(my_dc(;    wglMakeCurrent(my_dc, my_rc(;

这确实让您认为呈现上下文绑定到此特定设备上下文,并且仅对其有效。但事实并非如此。关键部分是注释(设置像素格式(。呈现上下文是为特定的 DC 类创建的,更准确地说:为具有相同像素格式的 DC。所以下面的代码是完全有效的:

   window_1 = 主窗口,window_2 = 您的窗口    HDC dc_1 = GetDC(window_1(;    Set_pixel_format_for_dc_1((;平常的东西    HGLRC rc = wglCreateContext(dc_1(;    wglMakeCurrent(dc_1, rc(;    ultra_super_draw((;   //.....    HDC dc_2 = GetDC(window_2(;    获取dc_1的 PF 以确保它与 rc 兼容。    int pf_index = GetPixelFormat(dc_1(;    PIXELFORMATDESCRIPTOR pfd;    ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR((;    DescribePixelFormat(dc_1, pf_index, sizeof(PIXELFORMATDESCRIPTOR(, &pfd(;    SetPixelFormat(dc_2, pf_index, &pfd(;    wglMakeCurrent(dc_2, rc(;    another_awesome_render((;    wglMakeCurrent(NULL, NULL(;

如果您仍然不相信,MSDN:

wglMakeCurrent(hdc, hglrc(:hdc 参数必须引用 OpenGL 支持的绘图图面。它不必与创建 hglrc 时传递给 wglCreateContext 的 hdc 相同,但它必须位于同一设备上并具有相同的像素格式。

我想你已经熟悉这些电话了。现在,我不知道您的渲染必须满足哪些条件,但是如果没有其他要求,我认为从这一点上看没有任何困难:

   HDC my_dc = Create_my_DC((;   //...    无效my_new_render    {        可能您想保存当前绑定:        HDC current_dc = wglGetCurrentDC((;        HGLRC current_context = wglGetCurrentContext((;        wglMakeCurrent(my_dc, current_context(;        MyUltraSuperRender(...(;        wglMakeCurrent(current_dc, current_context(;    }

希望这对:)有所帮助

首先,您实际上应该为您的插件创建一个单独的OpenGL上下文,原因很简单,它为您提供了一个单独的状态空间,不会干扰主程序OpenGL上下文。

不过,您误解了有关多个渲染上下文的部分。一个进程完全可以拥有任意数量的 OpenGL 上下文。但是进程的每个线程一次只能绑定一个上下文。该绑定还包括上下文绑定到的窗口 DC。然而,随时更改上下文约束是完全合法的。您可以更改给定上下文绑定到的窗口,也可以切换上下文,或者同时执行这两项操作。

因此,在您的情况下,我建议您为插件创建一个自定义上下文,用于插件创建的所有窗口。

您的简单上下文"创建"代码失败的原因很简单:您的窗口很可能没有设置像素格式描述符。

我建议您使用以下方法来创建新窗口和上下文:

/* first get hold of the HDC/HRC of the parent */
HDC parentDC = wglGetCurrentDC();
HRC parentRC = wglGetCurrentContext();
int pixelformatID = GetPixelFormat(parentDC);
/* we use the same PFD as the parent */
PIXELFORMATDESCRIPTOR pixelformat;
memset(pixelformat, 0, sizeof(pixelformat);
DescribePixelFormat(parentDC, pixelformatID, sizeof(pixelformat), &pixelformat);
/* create a window and set it's pixelformat to the parent one's */
HWND myWND = create_my_window();
HDC  myDC = GetDC(myWND);
SetPixelFormat(myDC, pixelformatID, &pixelformat);
/* finally we can create a rendering context
 * it doesn't matter if we create it against
 * the parent or our own DC.
 */
HRC myRC = wglCreateContext(myDC);
/* we're done here... */

现在,每当你的插件想要渲染一些东西时,它应该绑定自己的上下文,做它的事情并绑定之前绑定的上下文:

HDC prevDC = wglGetCurrentDC();
HRC prevRC = wglGetCurrentContext();
wglMakeCurrent(myDC, myRC);
/* do OpenGL stuff */
wglMakeCurrent(prevDC, prevRC);