通过虚拟窗口将OpenGL上下文渲染到裁剪的图像

9ceoxa92  于 2023-01-20  发布在  其他
关注(0)|答案(1)|浏览(154)

我正在尝试将OpenGL场景渲染为图像,而不渲染到任何窗口。为了在OpenGL中进行渲染调用,我仍然需要一个窗口句柄来初始化GL上下文。因此,我通过GetDC(0)将GL上下文绑定到"默认窗口句柄",生成的图像看起来很好。但是,使用"默认窗口句柄"的问题在于当呈现调用发生时整个屏幕 Flink 。
命令发送后,场景被渲染,在交换缓冲区之前,我通过glReadPixels将场景保存为128x128的图像。注意,视口也被设置为0, 0, 128, 128
由于无法摆脱恼人的屏幕 Flink ,我决定为GL上下文创建一个虚拟窗口。这就是我如何做到的:

// Initialize Dummy Window custom class
    WNDCLASSEX wincl{0};
    wincl.hInstance = (HINSTANCE)GetModuleHandle(NULL);
    wincl.lpszClassName = _T("GLDummyWCL");
    wincl.lpfnWndProc = WinProc;
    wincl.style = CS_DBLCLKS;
    wincl.cbSize = sizeof(WNDCLASSEX);
    wincl.lpszMenuName = NULL;
    wincl.cbClsExtra = 0;
    wincl.cbWndExtra = 0;
    wincl.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
    RegisterClassEx(&wincl);

    // Initialize dummy window and show it as HIDDEN
    hDummyWindow = CreateWindowEx(

        0,                              
        wincl.lpszClassName,            
        _T("GLDummyWindow"),    
        WS_BORDER,                      
        0,                              
        0,                              
        128,                    
        128,                      
        HWND_DESKTOP,   
        NULL, 
        (HINSTANCE)GetModuleHandle(NULL),
        NULL
    );

    //SetWindowLong(hDummyWindow, GWL_STYLE, 0);
    SetWindowLong(hDummyWindow, GWL_STYLE, GetWindowLong(hDummyWindow, GWL_STYLE) & ~(WS_CAPTION)); // Remove title bar
    ShowWindow(hDummyWindow, SW_HIDE);

    // Initialize OpenGL Context
    unsigned int PixelFormat;
    static PIXELFORMATDESCRIPTOR pfd;

    HDC hDC = GetDC(hDummyWindow); // GetDC(0);
    PixelFormat = ChoosePixelFormat(hDC, &pfd);
    SetPixelFormat(hDC, PixelFormat, &pfd);
    HGLRC hRC = wglCreateContext(hDC);

    wglMakeCurrent(hDC, hRC);

这是我的渲染函数的样子:

glViewport(0, 0, 128, 128);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Bind vertex arrays, uniforms, then render primitives
    // ...

    SaveSceneToImage();

    SwapBuffers(hDC);

以及将3D场景保存为图像的功能

void SaveSceneToImage() {

    unsigned char data[3 * 128 * 128 ] = {0};
    glReadPixels(0, 0, 128, 128, GL_RGB, GL_UNSIGNED_BYTE, data);

    // Save to file
    // ...
}

当把GL上下文绑定到一个实际的窗口句柄时,屏幕 Flink 停止了。但是,一个新的问题出现了。
图像被裁剪。这是它应该看起来的样子。当使用GetDC(0)时它的工作原理:

这就是结果:

看到它是如何向下移动的了吗?为什么会这样呢?我试着删除窗口的边框,但是即使删除所有的样式也无济于事。改变glViewportglReadPixels中的视口参数也没有任何作用。例如,增加y参数会进一步移动它。我也希望不必修改这些。
是否需要修改窗口的其他内容?
注意,窗口充当上下文的呈现转储,因为没有窗口就没有GL上下文。
而且,这是我唯一愿意用于"无窗口"上下文创建的方法。

rqqzpn5f

rqqzpn5f1#

我无法解释你所看到的转变,但我会提供一个替代解决方案:
事实上,你不能可靠地渲染到隐藏窗口。即使它是可见的,你也不能可靠地使用它做任何事情,除了渲染到屏幕上可见的部分。这是因为渲染到默认帧缓冲区时会发生“像素所有权测试”。
进行离屏渲染的正确方法是像您一样创建一个带有OpenGL上下文的虚拟窗口,然后创建一个帧缓冲对象(FBO),渲染到该FBO,并从那里检索数据。由于FBO完全根据您的规范进行分配,这很可能会解决您的问题。

相关问题