Search code examples
pythonpython-3.xopenglscenepyopengl

OpenGL - Render same scene from different angles without redrawing everything


I have a scene that I'm trying to render in all directions (later stitched together, outside OpenGL).

Currently for creating each frame - I redraw the entire scene 4 times (front, right, back, left). Can I somehow just render the 4 cubes together without redrawing the entire scene 4 times?

Here is a sample code that I use (Specifically I use PyOpenGL - But that doesn't really matter):

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

# Draws some model (The real code draws a much more complicated model)
def draw_model():
    glBegin(GL_QUADS)
    glColor3f(1.0, 1.0, 1.0)
    glVertex(10, 10, 0); glVertex(10, 10, 3); glVertex(10, -10, 3); glVertex(10, -10, 0)

    glColor3f(1.0, 1.0, 0)
    glVertex(-10, 10, 0); glVertex(-10, 10, 3); glVertex(-10, -10, 3); glVertex(-10, -10, 0)

    glColor3f(1.0, 0, 1.0)
    glVertex(10, 10, 0); glVertex(10, 10, 3); glVertex(-10, 10, 3); glVertex(-10, 10, 0)

    glColor3f(0, 1.0, 0)
    glVertex(10, -10, 0); glVertex(10, -10, 3); glVertex(-10, -10, 3); glVertex(-10, -10, 0)
    glEnd()

# Reads the pixels to NP
def get_display_pixels(rendered_image_width, rendered_image_height):
    data = glReadPixels(0, 0, rendered_image_width, rendered_image_height, OpenGL.GL.GL_RGB, OpenGL.GL.GL_UNSIGNED_BYTE)
    return np.frombuffer(data, dtype=np.uint8).reshape(rendered_image_height, rendered_image_width, 3)[::-1]

DISPLAY_WIDTH = 900
DISPLAY_HEIGHT = 900

glfw.init()
glfw.window_hint(glfw.VISIBLE, False)
window = glfw.create_window(DISPLAY_WIDTH, DISPLAY_HEIGHT, "some window", None, None)
glfw.make_context_current(window)

gluPerspective(90, (DISPLAY_WIDTH / DISPLAY_HEIGHT), 0.01, 30)
glEnable(GL_TEXTURE_2D)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)

position = (0, 3, 1)
# Get cube 1
glPushMatrix()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
gluLookAt(*position, 1, 4, 1, 0, 0, 1)
draw_model()
cube1 = get_display_pixels(DISPLAY_WIDTH, DISPLAY_HEIGHT)
glPopMatrix()

# Get cube 2
glPushMatrix()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
gluLookAt(*position, 1, 2, 1, 0, 0, 1)
draw_model()
cube2 = get_display_pixels(DISPLAY_WIDTH, DISPLAY_HEIGHT)
glPopMatrix()

# Get cube 3
glPushMatrix()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
gluLookAt(*position, -1, 2, 1, 0, 0, 1)
draw_model()
cube3 = get_display_pixels(DISPLAY_WIDTH, DISPLAY_HEIGHT)
glPopMatrix()

# Get cube 4
glPushMatrix()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
gluLookAt(*position, -1, 4, 1, 0, 0, 1)
draw_model()
cube4 = get_display_pixels(DISPLAY_WIDTH, DISPLAY_HEIGHT)
glPopMatrix()

cv2.imwrite(r"C:\temp\image1.png", cube1)
cv2.imwrite(r"C:\temp\image2.png", cube2)
cv2.imwrite(r"C:\temp\image3.png", cube3)
cv2.imwrite(r"C:\temp\image4.png", cube4)

glfw.destroy_window(window)
glfw.terminate()

Solution

  • The solution was achieved using the idea by "Rabbid76" in the comment.

    Moving all of the vertices to a VBO and then drawing them all at once gives the needed performance improvement