在python中没有可见窗口的OpenGL渲染视图

Posted

技术标签:

【中文标题】在python中没有可见窗口的OpenGL渲染视图【英文标题】:OpenGL render view without a visible window in python 【发布时间】:2018-08-01 07:26:26 【问题描述】:

我需要渲染一些场景。我设法使用 pyopengl 和 pygame 在 python 中做到这一点。问题是它会在短时间内创建一个窗口。

我想渲染相同的图像并保存它,而不创建可见窗口(或者可能根本不创建窗口,甚至没有 pygame)。

import cv2
import numpy as np
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *

def main():
    DISPLAY_WIDTH = 900
    DISPLAY_HEIGHT = 900

    pygame.init()
    pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT), DOUBLEBUF | OPENGL)
    gluPerspective(90, (DISPLAY_WIDTH / DISPLAY_HEIGHT), 0.01, 12)

    glEnable(GL_TEXTURE_2D)
    glEnable(GL_DEPTH_TEST)
    glDepthFunc(GL_LEQUAL)

    glRotatef(-90, 1, 0, 0) # Straight rotation
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glRotatef(285, 0, 0, 1) # Rotate yaw
    glTranslatef(-5, -3, -2) # Move to position

    # Draw rectangle
    glBegin(GL_QUADS)
    glColor3f(1, 0, 0)
    glVertex3f(2, 2, 0)
    glVertex3f(2, 2, 2)
    glVertex3f(2, 6, 2)
    glVertex3f(2, 6, 0)
    glEnd()

    image_buffer = glReadPixels(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, OpenGL.GL.GL_RGB, OpenGL.GL.GL_UNSIGNED_BYTE)
    image = np.frombuffer(image_buffer, dtype=np.uint8).reshape(DISPLAY_WIDTH, DISPLAY_HEIGHT, 3)

    cv2.imwrite(r"C:\temp\image.png", image)

    pygame.quit()


if __name__ == "__main__":
    main()

【问题讨论】:

我只知道pygame.display.iconify() 这确实使窗口无法聚焦。但它仍然是在任务栏上创建的。我认为最好的解决方案就是完全避免 pygame 无法使用高于 1.0 的 OpenGL 版本创建 OpenGL 屏幕外上下文。见Creating OpenGL context without window 另见Hiding pygame display 【参考方案1】:

我想渲染相同的图像并保存它,而不创建可见窗口

无法在没有任何窗口的情况下创建版本高于 1.0 的 OpenGL Context。 查看问题的答案Creating OpenGL context without window。

但可以使用完全隐藏的窗口进行“离屏”渲染。 遗憾的是,无法使用 Pygame 创建最初隐藏的窗口。 只有在 pygame.display.iconify() 创建窗口后才能隐藏它。 另见Hiding pygame display。

但是可以通过将window hint VISIBLE 设置为False 来使用GLFW 库创建一个最初隐藏的窗口。

glfw 库可以在glfw 1.7.0 找到。

代码可能如下所示:

import cv2
import numpy as np
from OpenGL.GL import *
from OpenGL.GLU import *
import glfw

def main():
    DISPLAY_WIDTH = 900
    DISPLAY_HEIGHT = 900

    # Initialize the library
    if not glfw.init():
        return
    # Set window hint NOT visible
    glfw.window_hint(glfw.VISIBLE, False)
    # Create a windowed mode window and its OpenGL context
    window = glfw.create_window(DISPLAY_WIDTH, DISPLAY_HEIGHT, "hidden window", None, None)
    if not window:
        glfw.terminate()
        return

    # Make the window's context current
    glfw.make_context_current(window)

    gluPerspective(90, (DISPLAY_WIDTH / DISPLAY_HEIGHT), 0.01, 12)

    glEnable(GL_TEXTURE_2D)
    glEnable(GL_DEPTH_TEST)
    glDepthFunc(GL_LEQUAL)

    glRotatef(-90, 1, 0, 0) # Straight rotation
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glRotatef(285, 0, 0, 1) # Rotate yaw
    glTranslatef(-5, -3, -2) # Move to position

    # Draw rectangle
    glBegin(GL_QUADS)
    glColor3f(1, 0, 0)
    glVertex3f(2, 2, 0)
    glVertex3f(2, 2, 2)
    glVertex3f(2, 6, 2)
    glVertex3f(2, 6, 0)
    glEnd()

    image_buffer = glReadPixels(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, OpenGL.GL.GL_RGB, OpenGL.GL.GL_UNSIGNED_BYTE)
    image = np.frombuffer(image_buffer, dtype=np.uint8).reshape(DISPLAY_WIDTH, DISPLAY_HEIGHT, 3)

    cv2.imwrite(r"C:\temp\image.png", image)

    glfw.destroy_window(window)
    glfw.terminate()

if __name__ == "__main__":
    main()

【讨论】:

这对我在 ubuntu 上的 glfw3 不起作用,它可以用作屏幕录像机。

以上是关于在python中没有可见窗口的OpenGL渲染视图的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 着色器编译但窗口中未出现渲染

使用 opencl 将软件渲染到 opengl 2d 视图 [关闭]

将 OpenGL 绘制到离屏位图

将 Ortho 切换到 OpenGL HUD 的透视图

检查顶点在相机视图中是不是可见并渲染或被遮挡

OpenGL:如何设置 OpenGL 只渲染到 FBO,不输出到屏幕/窗口/控件?