简体   繁体   中英

Python OpenGL not working properly when trying to color 3D objects

I am getting started with PyOpenGL and when I tried coloring, it just gave me some fancy results

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)

I am using python 3.7 for it,
I have tried using python 3.5 but the result was same pygame version 1.9.6,
PyOpenGL version 3.1.5

输出

I guess the issue could be due to Python Versions but I am not Sure<


Edit :

New code after adding the suggestions from the answer.

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)

I had a similar problem. The root cause was graphics hardware related. My pygame 1.9.4+pyOpenGL 3.1.2 used to render correctly. Recently my Intel and Nvidia drivers+control applications were updated and pygame+pyOpenGL was not rendered correctly.

Bad render

I upgraded to pygame 2.0.1+pyOpenGL 3.1.5, but the problem persisted.

My solution was to change in the Nvidia Control Panel's Global Settings the option

  • Preferred graphics processor: "Auto-select" to
  • Preferred graphics processor: "High performance NVIDIA processor"

as shown in the following screenshots of Nvidia's Control Panel:

Nvidia Control Panel with Preferred graphics processor set to "Auto-select"

Nvidia Control Panel with Preferred graphics processor set to "High performance NVIDIA processor"

with this change in the graphics hardware settings, pygame+pyOpenGL were rendered correctly once again producing the right shading of the 3D surfaces as in the following image.

Good render

In my case, my laptop (Dell Precision 7530) has an integrated graphics card (Intel UHD 630) and a high performance graphics card (Nvidia Quadro P2000). With the original setting from factory never experienced this problem (my laptop is two years old). Apparently after some driver/control panel update the configuration changed.

There is another "dirty" fix to the rendering problem, which I comment in case might be useful under other situations. This fix is to turn off double buffering and do it manually, ie:

At initialization issue the command:

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

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

At the end after all GL drawing commands force their execution:

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

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

Probably this solution is useful when the available graphic hardware is not able to do double buffering.

You missed to enable the Depth Test and if you want to use the Depth Test t, you need to ensure that the default frame buffer has a depth buffer. Set the depth buffer size attribute ( GL_DEPTH_SIZE ) with pygame.display.gl_set_attribute (Try a size of 24, if that doesn't work then switch to 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:
        # [...]

The default depth test function is GL_LESS . If the depth test fails, a fragment is discarded. Hence if a fragment is drawn in a location where another fragment was previously drawn that was closer to the camera, the new fragment will be discarded.


All the matrix operations like glRotate , glTranslate , gluPerspective , etc. specify a new matrix and multiply the current matrix by the new matrix.

If you want to reset the view, then you have to load the Identity Matrix before by 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 provides different current matrices (see glMatrixMode ). The projection matrix should be set to the current projection matrix ( GL_PROJECTION ) and the model view matrix to the current model view matrix ( 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)

Complete example:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM