OpenGL render view without a visible window in python
Asked Answered
M

1

9

I need to render some scene. I managed to do it in python using pyopengl and pygame. The problem is that it creates a window for a short period of time.

I want to render the same image and save it, without creating a visible window (Or possibly without creating a window at all, and even without 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()
Muskogee answered 1/8, 2018 at 7:26 Comment(4)
The only thing I know is pygame.display.iconify()Injustice
This indeed makes the window not to focus. But it is still created on the taskbar. I think the best solution is just to avoid pygame completelyMuskogee
It is not possible to create an OpenGL offscreen context with a OpenGL version above 1.0. See Creating OpenGL context without windowInjustice
See also Hiding pygame displayInjustice
I
7

I want to render the same image and save it, without creating a visible window

It is not possible to create an OpenGL Context with an version above 1.0 without any window.
See the answer to the question Creating OpenGL context without window.

But it is possible to use a completely hidden window for "offscreen" rendering.

Sadly it is not possible to create a initially hidden window with Pygame.
It is only possible to hide a window after it was created by pygame.display.iconify(). See also Hiding pygame display.

But it is possible to create a initially hidden window with the GLFW library by setting the window hint VISIBLE to False.

The glfw library can be found at glfw 1.7.0.

The code may look like this:

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()
Injustice answered 3/8, 2018 at 12:21 Comment(1)
This doesn't work for me with glfw3 on ubuntu, it functions as a screen recorder.Inclined

© 2022 - 2024 — McMap. All rights reserved.