简体   繁体   English

尝试为 3D 对象着色时,Python OpenGL 无法正常工作

[英]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我开始使用 PyOpenGL,当我尝试着色时,它给了我一些奇特的结果

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,我正在使用 python 3.7,
I have tried using python 3.5 but the result was same pygame version 1.9.6,我曾尝试使用 python 3.5,但结果是相同的 pygame 版本 1.9.6,
PyOpenGL version 3.1.5 PyOpenGL 3.1.5 版

输出

I guess the issue could be due to Python Versions but I am not Sure<我想这个问题可能是由于 Python 版本造成的,但我不确定<


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.我的 pygame 1.9.4+pyOpenGL 3.1.2 用于正确渲染。 Recently my Intel and Nvidia drivers+control applications were updated and pygame+pyOpenGL was not rendered correctly.最近我的 Intel 和 Nvidia 驱动程序+控制应用程序更新了,pygame+pyOpenGL 没有正确呈现。

Bad render糟糕的渲染

I upgraded to pygame 2.0.1+pyOpenGL 3.1.5, but the problem persisted.我升级到pygame 2.0.1+pyOpenGL 3.1.5,但问题依旧。

My solution was to change in the Nvidia Control Panel's Global Settings the option我的解决方案是在 Nvidia 控制面板的全局设置中更改选项

  • Preferred graphics processor: "Auto-select" to首选图形处理器:“自动选择”到
  • Preferred graphics processor: "High performance NVIDIA processor"首选图形处理器:“高性能 NVIDIA 处理器”

as shown in the following screenshots of Nvidia's Control Panel:如以下 Nvidia 控制面板的屏幕截图所示:

Nvidia Control Panel with Preferred graphics processor set to "Auto-select"首选图形处理器设置为“自动选择”的 Nvidia 控制面板

Nvidia Control Panel with Preferred graphics processor set to "High performance NVIDIA processor"将首选图形处理器设置为“高性能 NVIDIA 处理器”的 Nvidia 控制面板

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.随着图形硬件设置的这一变化,pygame+pyOpenGL 再次正确渲染,产生 3D 表面的正确阴影,如下图所示。

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).就我而言,我的笔记本电脑(Dell Precision 7530)有一个集成显卡(Intel UHD 630)和一个高性能显卡(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:最后,在所有 GL 绘图命令强制执行它们之后:

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.您错过了启用深度测试,如果您想使用深度测试t,您需要确保默认帧缓冲区具有深度缓冲区。 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):使用pygame.display.gl_set_attribute设置深度缓冲区大小属性( GL_DEPTH_SIZE )(尝试大小为 24,如果不起作用则切换到 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 .默认的深度测试函数是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.所有矩阵运算,如glRotateglTranslategluPerspective等,指定一个新矩阵并将当前矩阵乘以新矩阵。

If you want to reset the view, then you have to load the Identity Matrix before by glLoadIdentity :如果要重置视图,则必须先通过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 ).旧版 OpenGL 提供了不同的当前矩阵(请参阅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 ):投影矩阵应设置为当前投影矩阵( GL_PROJECTION ),模型视图矩阵应设置为当前模型视图矩阵( 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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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