Python OpenGL no funciona correctamente al intentar colorear objetos 3D

Sep 27 2020

Estoy comenzando con PyOpenGL y cuando intenté colorear, me dio algunos resultados elegantes

import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
verticies = (
    (-1, 1, -1),
    (1, 1, -1),
    (1, -1, -1),
    (-1, -1, -1),
    (-1, -1, 1),
    (-1, 1, 1),
    (1, 1, 1),
    (1, -1, 1)
)
edges=(
    (0,1),
    (0,5),
    (1,2),
    (1,6),
    (2,3),
    (2,7),
    (0,3),
    (3,4),
    (4,7),
    (6,7),
    (5,6),
    (4,5)
)

surfaces = (
    (0,1,2,3),
    (0,1,6,5),
    (0,3,4,5),
    (3,2,7,4),
    (1,2,7,6),
    (4,5,6,7),
)

colors= (




)
def color_in_face(color, face_index):
    for vertex in surfaces[face_index]:
        glColor3fv(color)
        glVertex3fv(verticies[vertex])

def Cube():
    glBegin(GL_QUADS)
    color_in_face((1,0,0), 0)
    color_in_face((0,1,0), 1)
    color_in_face((0,0,1), 2)
    color_in_face((1,1,0), 3)
    color_in_face((0,1,1), 4)
    color_in_face((1,0,1), 5)
    glEnd()

    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glVertex3fv(verticies[vertex])
    glEnd()

def main():
    to_rotate = False
    pygame.init()
    display = (800,600)
    pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
    gluPerspective(45,  (display[0]/display[1]), 0.1, 70.0)
    glTranslatef(0.0,0.0, -5)

    glRotatef(0,0,0,0)
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    to_rotate = "left"
                elif event.key == pygame.K_RIGHT:
                    to_rotate = "right"
                elif event.key == pygame.K_UP:
                    to_rotate = "up"
                elif event.key == pygame.K_DOWN:
                    to_rotate = "down"
                elif event.key == pygame.K_a:
                    to_rotate = "t-l"
                elif event.key == pygame.K_s:
                    to_rotate = "t-r"
                elif event.key == pygame.K_z:
                    to_rotate = "b-l"
                elif event.key == pygame.K_x:
                    to_rotate = "b-r"
                elif event.key == pygame.K_q:
                    to_rotate = "stop"
                elif event.key == pygame.K_w:
                    to_rotate = "reload"

        if to_rotate!=None:
            if to_rotate==False:
                glRotatef(0, 0, 0, 0)
            elif to_rotate=="left":
                glRotatef(0.5, 0, 1, 0)
            elif to_rotate=="right":
                glRotatef(0.5, 0, -1, 0)
            elif to_rotate=="up":
                glRotatef(0.5, 1, 0, 0)
            elif to_rotate=="down":
                glRotatef(0.5, -1, 0, 0)
            elif to_rotate=="t-l":
                glRotatef(0.5, 1, 1, 0)
            elif to_rotate=="t-r":
                glRotatef(0.5, 1, -1, 0)
            elif to_rotate=="b-l":
                glRotatef(0.5, -1, 1, 0)
            elif to_rotate=="b-r":
                glRotatef(0.5, -1, -1, 0)
            elif to_rotate=="stop":
                glRotatef(0, 0, 0, 0)
            elif to_rotate=="reload":
                pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
                gluPerspective(45, (display[0] / display[1]), 0.1, 50.0)
                glTranslatef(0.0, 0.0, -5)
                glRotatef(0, 0, 0, 0)

        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        Cube()
        pygame.display.flip()
        pygame.time.wait(10)

main()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            quit()
    glRotatef(1, 1, 1, 1)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    Cube()
    pygame.display.flip()
    pygame.time.wait(10)

Estoy usando python 3.7,
he intentado usar python 3.5 pero el resultado fue la misma versión 1.9.6 de
pygame , versión 3.1.5 de PyOpenGL

Supongo que el problema podría deberse a las versiones de Python, pero no estoy seguro <


Editar :

Nuevo código después de agregar las sugerencias de la respuesta.

import pygame
from pygame.locals import *

from OpenGL.GL import *
from OpenGL.GLU import *

verticies = (
    (-1, 1, -1),
    (1, 1, -1),
    (1, -1, -1),
    (-1, -1, -1),
    (-1, -1, 1),
    (-1, 1, 1),
    (1, 1, 1),
    (1, -1, 1)
)
edges = (
    (0, 1),
    (0, 5),
    (1, 2),
    (1, 6),
    (2, 3),
    (2, 7),
    (0, 3),
    (3, 4),
    (4, 7),
    (6, 7),
    (5, 6),
    (4, 5)
)

surfaces = (
    (0, 1, 2, 3),
    (0, 1, 6, 5),
    (0, 3, 4, 5),
    (3, 2, 7, 4),
    (1, 2, 7, 6),
    (4, 5, 6, 7),
)

colors = (
    (1, 0, 0),
    (0, 1, 0),
    (0, 0, 1),
    (0, 0, 0),
    (1, 1, 1),
    (0, 1, 1),
    (1, 0, 0),
    (0, 1, 0),
    (0, 0, 1),
    (0, 0, 0),
    (1, 1, 1),
    (0, 1, 1)
)


def Cube():
    glBegin(GL_QUADS)
    for surface in surfaces:
        x = 0

        for vertex in surface:
            x += 1
            glColor3fv(colors[x])
            glVertex3fv(verticies[vertex])

    glEnd()

    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glVertex3fv(verticies[vertex])
    glEnd()


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

    glEnable(GL_DEPTH_TEST)
    pygame.display.gl_set_attribute(GL_DEPTH_SIZE, 24)

    gluPerspective(45, (display[0] / display[1]), 0.1, 70.0)
    glTranslatef(0.0, 0.0, -5)

    glRotatef(0, 0, 0, 0)
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    to_rotate = "left"
                elif event.key == pygame.K_RIGHT:
                    to_rotate = "right"
                elif event.key == pygame.K_UP:
                    to_rotate = "up"
                elif event.key == pygame.K_DOWN:
                    to_rotate = "down"
                elif event.key == pygame.K_a:
                    to_rotate = "t-l"
                elif event.key == pygame.K_s:
                    to_rotate = "t-r"
                elif event.key == pygame.K_z:
                    to_rotate = "b-l"
                elif event.key == pygame.K_x:
                    to_rotate = "b-r"
                elif event.key == pygame.K_q:
                    to_rotate = "stop"
                elif event.key == pygame.K_w:
                    to_rotate = "reload"
                elif event.key == pygame.K_f:
                    to_rotate = "f"
                elif event.key == pygame.K_v:
                    to_rotate = "v"

        if to_rotate != None:
            if to_rotate == False:
                glRotatef(0, 0, 0, 0)
            elif to_rotate == "left":
                glRotatef(0.5, 0, 1, 0)
            elif to_rotate == "right":
                glRotatef(0.5, 0, -1, 0)
            elif to_rotate == "up":
                glRotatef(0.5, 1, 0, 0)
            elif to_rotate == "down":
                glRotatef(0.5, -1, 0, 0)
            elif to_rotate == "t-l":
                glRotatef(0.5, 1, 1, 0)
            elif to_rotate == "t-r":
                glRotatef(0.5, 1, -1, 0)
            elif to_rotate == "b-l":
                glRotatef(0.5, -1, 1, 0)
            elif to_rotate == "b-r":
                glRotatef(0.5, -1, -1, 0)
            elif to_rotate == "stop":
                glRotatef(0, 0, 0, 0)

            elif to_rotate == "f":
                glRotatef(0.5, 0, 0, 1)
            elif to_rotate == "v":
                glRotatef(0.5, 0, 0, -1)

            elif to_rotate == "reload":
                pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
                gluPerspective(45, (display[0] / display[1]), 0.1, 50.0)
                glTranslatef(0.0, 0.0, -5)
                glRotatef(0, 0, 0, 0)

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        Cube()
        pygame.display.flip()
        pygame.time.wait(10)


main()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            quit()
    glRotatef(1, 1, 1, 1)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    Cube()
    pygame.display.flip()
    pygame.time.wait(8)

Respuestas

2 MATT Feb 24 2021 at 10:17

Tuve un problema similar. La causa principal estaba relacionada con el hardware de gráficos. Mi pygame 1.9.4 + pyOpenGL 3.1.2 solía renderizarse correctamente. Recientemente, mis aplicaciones de control + controladores Intel y Nvidia se actualizaron y pygame + pyOpenGL no se procesó correctamente.

Mal renderizado

Actualicé a pygame 2.0.1 + pyOpenGL 3.1.5, pero el problema persistió.

Mi solución fue cambiar en la Configuración global del Panel de control de Nvidia la opción

  • Procesador de gráficos preferido: "Selección automática" para
  • Procesador de gráficos preferido: "Procesador NVIDIA de alto rendimiento"

como se muestra en las siguientes capturas de pantalla del Panel de control de Nvidia:

Panel de control de Nvidia con el procesador de gráficos preferido configurado en "Selección automática"

Panel de control de Nvidia con procesador de gráficos preferido configurado en "Procesador NVIDIA de alto rendimiento"

con este cambio en la configuración del hardware de gráficos, pygame + pyOpenGL se renderizaron correctamente una vez más produciendo el sombreado correcto de las superficies 3D como en la siguiente imagen.

Buen render

En mi caso, mi computadora portátil (Dell Precision 7530) tiene una tarjeta gráfica integrada (Intel UHD 630) y una tarjeta gráfica de alto rendimiento (Nvidia Quadro P2000). Con la configuración original de fábrica, nunca experimenté este problema (mi computadora portátil tiene dos años). Aparentemente, después de alguna actualización del controlador / panel de control, la configuración cambió.

Hay otra solución "sucia" para el problema de renderizado, que comento en caso de que pueda ser útil en otras situaciones. Esta solución consiste en desactivar el almacenamiento en búfer doble y hacerlo manualmente, es decir:

En la inicialización, emita el comando:

pygame.display.set_mode(display, OPENGL)   # <--- Note "DOUBLEBUF|" was removed

# [... GL drawing commands ...]

Al final, después de que todos los comandos de dibujo GL fuercen su ejecución:

glFlush()               # <--- Force the execution of GL commands
pygame.display.flip()   #      before pygame.display.flip()

# [...  rest of the code   ...]

Probablemente esta solución sea útil cuando el hardware gráfico disponible no sea capaz de hacer doble búfer.

1 Rabbid76 Sep 27 2020 at 16:06

No habilitó la prueba de profundidad y si desea utilizar la prueba de profundidad t, debe asegurarse de que el búfer de fotogramas predeterminado tenga un búfer de profundidad. Establezca el atributo de tamaño de búfer de profundidad ( GL_DEPTH_SIZE) con pygame.display.gl_set_attribute(Pruebe con un tamaño de 24, si eso no funciona, cambie a 16):

def main():
    to_rotate = False
    pygame.init()
    display = (800,600)

    pygame.display.gl_set_attribute(GL_DEPTH_SIZE, 24) # <--- set depth buffer size

    pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
    
    glEnable(GL_DEPTH_TEST) # <--- enable depth test
    
    gluPerspective(45,  (display[0]/display[1]), 0.1, 70.0)
    glTranslatef(0.0,0.0, -5)

    glRotatef(0,0,0,0)
    while True:
        # [...]

La función de prueba de profundidad predeterminada es GL_LESS. Si la prueba de profundidad falla, se descarta un fragmento. Por lo tanto, si un fragmento se dibuja en una ubicación donde se dibujó previamente otro fragmento que estaba más cerca de la cámara, el nuevo fragmento se descartará.


Todas las operaciones de la matriz como glRotate, glTranslate, gluPerspective, etc. especificar una nueva matriz y multiplicar la matriz actual por la nueva matriz.

Si desea restablecer la vista, debe cargar la Matriz de identidad antes de la siguiente manera glLoadIdentity:

def main():
    # [...]

    while True:
        # [...]

            
        elif to_rotate=="reload":

            glLoadIdentity()  # <--- load identity matrix

            gluPerspective(45, (display[0] / display[1]), 0.1, 50.0)
            glTranslatef(0.0, 0.0, -5)

Legacy OpenGL proporciona diferentes matrices actuales (ver glMatrixMode). La matriz de proyección debe establecerse en la matriz de proyección actual ( GL_PROJECTION) y la matriz de vista del modelo en la matriz de vista del modelo actual ( GL_MODELVIEW):

def main():
    # [...]
    
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(45,  (display[0]/display[1]), 0.1, 70.0)
    
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    glTranslatef(0.0,0.0, -5)

Ejemplo completo:

import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
verticies = (
    (-1, 1, -1),
    (1, 1, -1),
    (1, -1, -1),
    (-1, -1, -1),
    (-1, -1, 1),
    (-1, 1, 1),
    (1, 1, 1),
    (1, -1, 1)
)
edges=(
    (0,1),
    (0,5),
    (1,2),
    (1,6),
    (2,3),
    (2,7),
    (0,3),
    (3,4),
    (4,7),
    (6,7),
    (5,6),
    (4,5)
)

surfaces = (
    (0,1,2,3),
    (0,1,6,5),
    (0,3,4,5),
    (3,2,7,4),
    (1,2,7,6),
    (4,5,6,7),
)

colors= ()
def color_in_face(color, face_index):
    for vertex in surfaces[face_index]:
        glColor3fv(color)
        glVertex3fv(verticies[vertex])

def Cube():
    glBegin(GL_QUADS)
    color_in_face((1,0,0), 0)
    color_in_face((0,1,0), 1)
    color_in_face((0,0,1), 2)
    color_in_face((1,1,0), 3)
    color_in_face((0,1,1), 4)
    color_in_face((1,0,1), 5)
    glEnd()

    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glVertex3fv(verticies[vertex])
    glEnd()

def main():
    to_rotate = False
    pygame.init()
    display = (800,600)
    pygame.display.gl_set_attribute(GL_DEPTH_SIZE, 24)
    pygame.display.set_mode(display, DOUBLEBUF|OPENGL)
    
    glEnable(GL_DEPTH_TEST)
    
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(45,  (display[0]/display[1]), 0.1, 70.0)
    
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    glTranslatef(0.0,0.0, -5)
    
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    to_rotate = "left"
                elif event.key == pygame.K_RIGHT:
                    to_rotate = "right"
                elif event.key == pygame.K_UP:
                    to_rotate = "up"
                elif event.key == pygame.K_DOWN:
                    to_rotate = "down"
                elif event.key == pygame.K_a:
                    to_rotate = "t-l"
                elif event.key == pygame.K_s:
                    to_rotate = "t-r"
                elif event.key == pygame.K_z:
                    to_rotate = "b-l"
                elif event.key == pygame.K_x:
                    to_rotate = "b-r"
                elif event.key == pygame.K_q:
                    to_rotate = "stop"
                elif event.key == pygame.K_w:
                    to_rotate = "reload"

        if to_rotate=="left":
            glRotatef(0.5, 0, 1, 0)
        elif to_rotate=="right":
            glRotatef(0.5, 0, -1, 0)
        elif to_rotate=="up":
            glRotatef(0.5, 1, 0, 0)
        elif to_rotate=="down":
            glRotatef(0.5, -1, 0, 0)
        elif to_rotate=="t-l":
            glRotatef(0.5, 1, 1, 0)
        elif to_rotate=="t-r":
            glRotatef(0.5, 1, -1, 0)
        elif to_rotate=="b-l":
            glRotatef(0.5, -1, 1, 0)
        elif to_rotate=="b-r":
            glRotatef(0.5, -1, -1, 0)
        elif to_rotate=="reload":
            glLoadIdentity()
            glTranslatef(0.0, 0.0, -5)

        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
        Cube()
        pygame.display.flip()
        pygame.time.wait(10)

main()