【问题标题】:How can I draw inside two separate 3D windows within the same application on Windows using OpenGL?如何使用 OpenGL 在 Windows 上的同一应用程序中的两个单独的 3D 窗口内绘制?
【发布时间】:2023-03-21 15:55:01
【问题描述】:

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

第 3 方程序有一个使用 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);

但是最后一个函数失败了。 阅读the documentation of wglMakeCurrent 我注意到

一个线程可以有一个当前渲染上下文。通过多线程,一个进程可以拥有多个渲染上下文。

这是否意味着我的窗口需要在独立于 3rd 方程序的线程中运行?

【问题讨论】:

  • 如果您的窗口与第 3 方应用程序的窗口具有相同的像素格式,则不需要单独的线程。告诉我们如何准确地告诉我们wglMakeCurrent() failed 可能会有所帮助。

标签: c++ windows multithreading winapi opengl


【解决方案1】:

您没有发布 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); 超超画(); //..... HDC dc_2 = GetDC(window_2); //获取dc_1的PF以确保它与rc兼容。 int pf_index = GetPixelFormat(dc_1); 像素格式描述符 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); }

希望这会有所帮助:)

【讨论】:

    【解决方案2】:

    首先,您实际上应该为您的插件创建一个单独的 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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多