opengl render view without a visible window in python

  • Last Update :
  • Techknowledgy :

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()

Suggestion : 2

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.,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).,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

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()

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()

Suggestion : 3

Once you define the vertices, you can then do things with them. In this example, we want to draw lines between them. Defining the vertices is done with a simple list or tuple in Python. You can then pre-define some rules like what vertices make up a "surface" and between what vertices are the "edges," or lines that we want to have drawn between the vertices.,This is a simple PyGame event loop that is only checking for any exit, which is only looking for the literal "x" out. Continuing under this "while" statement:,Here, we've defined the location (x,y,z) of each vertex. I think it is best to envision this in "units." Try to think of these locations "spatially." With a cube, there are 8 "nodes" or vertices.,Each of the above tuples contains two numbers. Those numbers correspond to a vertex, and the "edge" is going to be drawn between those two vertices. We start with 0, since that's how Python and most programming languages work (the first element is 0). So, 0 corresponds to the first vertex we defined (1, -1, -1)... and so on.

Once you have everything, go ahead and open up IDLE and type in:

import pygame
import OpenGL

First, we're going to do some imports:

import pygame
from pygame.locals
import *
from OpenGL.GL
import *
from OpenGL.GLU
import *

For the first few videos, I go ahead and miss-spell vertices. Oops.

vertices = (
   (1, -1, -1),
   (1, 1, -1),
   (-1, 1, -1),
   (-1, -1, -1),
   (1, -1, 1),
   (1, 1, 1),
   (-1, -1, 1),
   (-1, 1, 1)
)

Now that we've got that, let's work on the required code to work with OpenGL to actually generate a cube:

def Cube():
   glBegin(GL_LINES)
for edge in edges:
   for vertex in edge:
   glVertex3fv(vertices[vertex])
glEnd()

That's it for our cube function. This function will create the cube, but now we want to display the cube and specify our perspective in the environment:

def main():
   pygame.init()
display = (800, 600)
pygame.display.set_mode(display, DOUBLEBUF | OPENGL)

Suggestion : 4

Avoid calling winId() on a QQuickWidget . This function triggers the creation of a native window, resulting in reduced performance and possibly rendering glitches. The entire purpose of QQuickWidget is to render Quick scenes without a separate native window, hence making it a native widget should always be avoided.,In addition to OpenGL, the software backend of Qt Quick also supports QQuickWidget . Other backends, for example OpenVG, are not compatible however and attempting to construct a QQuickWidget will lead to problems.,The offscreen window may be deleted (and recreated) during the life time of the QQuickWidget , particularly when the widget is moved to another QQuickWindow . If you need to know when the window has been replaced, connect to its destroyed() signal.,QQuickWidget is an alternative to using QQuickView and createWindowContainer() . The restrictions on stacking order do not apply, making QQuickWidget the more flexible alternative, behaving more like an ordinary widget.

QQuickWidget * view = new QQuickWidget;
view - > setSource(QUrl::fromLocalFile("myqmlfile.qml"));
view - > show();

Suggestion : 5

So when adding vegetation to a scene we don't want to see a square image of grass, but rather only show the actual grass and see through the rest of the image. We want to discard the fragments that show the transparent parts of the texture, not storing that fragment into the color buffer. , We'll soon be adding this windowed texture to the scene from the depth testing chapter, but first we'll discuss an easier technique to implement transparency for pixels that are either fully transparent or fully opaque. , The result is a sorted container object that stores each of the window positions based on their distance key value from lowest to highest distance. , Some effects do not care about partial transparency, but either want to show something or nothing at all based on the color value of a texture. Think of grass; to create something like grass with little effort you generally paste a grass texture onto a 2D quad and place that quad into your scene. However, grass isn't exactly shaped like a 2D square so you only want to display some parts of the grass texture and ignore the others.

Before we get into that we first need to learn how to load a transparent texture. To load textures with alpha values there's not much we need to change. stb_image automatically loads an image's alpha channel if it's available, but we do need to tell OpenGL our texture now uses an alpha channel in the texture generation procedure:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);

Also make sure that you retrieve all 4 color components of the texture in the fragment shader, not just the RGB components:

void main() {
   // FragColor = vec4(vec3(texture(texture1, TexCoords)), 1.0);
   FragColor = texture(texture1, TexCoords);
}

We create a small vector array where we add several glm::vec3 vectors to represent the location of the grass leaves:

vector<glm::vec3> vegetation;
   vegetation.push_back(glm::vec3(-1.5f, 0.0f, -0.48f));
   vegetation.push_back(glm::vec3( 1.5f, 0.0f, 0.51f));
   vegetation.push_back(glm::vec3( 0.0f, 0.0f, 0.7f));
   vegetation.push_back(glm::vec3(-0.3f, 0.0f, -2.3f));
   vegetation.push_back(glm::vec3( 0.5f, 0.0f, -0.6f));

This happens because OpenGL by default does not know what to do with alpha values, nor when to discard them. We have to manually do this ourselves. Luckily this is quite easy thanks to the use of shaders. GLSL gives us the discard command that (once called) ensures the fragment will not be further processed and thus not end up into the color buffer. Thanks to this command we can check whether a fragment has an alpha value below a certain threshold and if so, discard the fragment as if it had never been processed:

#version 330 core
out vec4 FragColor;

in vec2 TexCoords;

uniform sampler2D texture1;

void main() {
   vec4 texColor = texture(texture1, TexCoords);
   if (texColor.a < 0.1)
      discard;
   FragColor = texColor;
}
GL_CLAMP_TO_EDGE
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
GL_CLAMP_TO_EDGE
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

Suggestion : 6

This module allows applications to create and display windows with an OpenGL context. Windows can be created with a variety of border styles or set fullscreen.,This event is triggered when the window first appears, and any time the contents of the window is invalidated due to another window obscuring it.,To render into a window, you must first call switch_to, to make it the current OpenGL context. If you use only one window in the application, there is no need to do this.,This event can be triggered by clicking on another application window. When a window is deactivated it no longer has the keyboard focus.

from pyglet.window
import Window
win = Window(width = 640, height = 480)
@win.event
def on_key_press(symbol, modifiers):
   #...handle this event...
@win.event
def on_draw():
   #...drawing code...
from pyglet
import app
app.run()
win = Window(fullscreen = True)
win.set_exclusive_mouse()
display = pyglet.canvas.get_display()
screens = display.get_screens()
windows = []
for screen in screens:
   windows.append(window.Window(fullscreen = True, screen = screen))