Как PyOpenGL выбирает цвета для рисования каждой фигуры?

Я нахожусь в середине проекта PyQt5 PyOpenGL. Я пытаюсь нарисовать белый каркасный куб с кучей цветных сплошных кубов. Каркасные кубы рисуются из списка точек кортежа и списка ссылок кортежа на эти точки. Сплошные кубы рисуются из списка ссылок кортежей на точки. Вот код куба:

class cube():
    render = True
    solid = False
    color = (1, 1, 1)

    def config(self, x, y, z, size = 0.1, solid = False, color = (1, 1, 1)):
        self.solid = solid
        self.color = color
        self.size = size / 2
        s = self.size
        self.vertices = [
                         (-s + x, s + y, -s + z),
                         (s + x, s + y, -s + z),
                         (s + x, -s + y, -s + z),
                         (-s + x, -s + y, -s + z),
                         (-s + x, s + y, s + z),
                         (s + x, s + y, s + z),
                         (s + x, -s + y, s + z),
                         (-s + x, -s + y, s + z)
                       ]
        self.edges = [
                      (0,1), (0,3), (0,4), (2,1),
                      (2,3), (2,6), (7,3), (7,4),
                      (7,6), (5,1), (5,4), (5,6)
                     ]
        self.facets = [
                       (0, 1, 2, 3), (0, 1, 6, 5),
                       (0, 3, 7, 4), (6, 5, 1, 2),
                       (6, 7, 4, 5), (6, 7, 3, 2)
                      ]
    def show(self):
        self.render = True
    def hide(self):
        self.render = False

Чтобы визуализировать куб, я получаю размер списка, хранящегося в моем классе mainWindow, а затем добавляю экземпляр класса куба в этот список. Затем я могу сослаться на этот экземпляр, используя размер перед добавлением. Вот код функции рендеринга:

def paintGL(self):
    glLoadIdentity()
    gluPerspective(45, self.width / self.height, 0.1, 110.0)    #set perspective?
    glTranslatef(0, 0, self.zoomLevel)    #I used -10 instead of -2 in the PyGame version.
    glRotatef(self.rotateDegreeV, 1, 0, 0)    #I used 2 instead of 1 in the PyGame version.
    glRotatef(self.rotateDegreeH, 0, 0, 1)
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

    if len(self.shapes) != 0:
        glBegin(GL_LINES)
        for s in self.shapes:
            if s.render and not s.solid:
                for e in s.edges:
                    for v in e:
                        glVertex3fv(s.vertices[v])
        glEnd()

        glBegin(GL_QUADS)
        for s in self.shapes:
            if s.render and s.solid:
                for f in s.facets:
                    for v in f:
                        glColor3fv(s.color)
                        glVertex3fv(s.vertices[v])
        glEnd()

Если я визуализирую только один куб в каркасе, он отображается белым. Если я добавлю красный сплошной куб и синий сплошной куб после него, каркасный куб будет окрашен последним использованным цветом, каким бы он ни был. Например:

    self.shapes.append(self.cube())
    self.shapes.append(self.cube())
    self.shapes.append(self.cube())
    self.shapes[0].config(-1, 0, 0, size = 0.5, solid = False)
    self.shapes[1].config(0, 0, 0, size = 0.5, solid = True, color = (1, 0, 0))
    self.shapes[2].config(1, 0, 0, size = 0.5, solid = True, color = (0, 0, 1))

Результат:

кубы

Как сделать так, чтобы мои каркасы отображались белым цветом по умолчанию или другим цветом? Я ожидаю, что glClear() сбросит его и нарисует каркас белым цветом, учитывая, что он первый.

Вот полный код:

import sys
from PyQt5.QtWidgets import (
                             QApplication, QMainWindow, QSlider,
                             QOpenGLWidget, QLabel, QPushButton
                            )
from PyQt5.QtCore import Qt
from OpenGL.GL import (
                       glLoadIdentity, glTranslatef, glRotatef,
                       glClear, glBegin, glEnd,
                       glColor3fv, glVertex3fv,
                       GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT,
                       GL_QUADS, GL_LINES
                      )
from OpenGL.GLU import gluPerspective

class mainWindow(QMainWindow):    #Main class.
    shapes = []    #this will hold instances of the following classes: 
    zoomLevel = -10
    rotateDegreeV = -90
    rotateDegreeH = 0

    class cube():
        render = True
        solid = False
        color = (1, 1, 1)

        def config(self, x, y, z, size = 0.1, solid = False, color = (1, 1, 1)):
            self.solid = solid
            self.color = color
            self.size = size
            s = self.size / 2
            self.vertices = [
                             (-s + x, s + y, -s + z),
                             (s + x, s + y, -s + z),
                             (s + x, -s + y, -s + z),
                             (-s + x, -s + y, -s + z),
                             (-s + x, s + y, s + z),
                             (s + x, s + y, s + z),
                             (s + x, -s + y, s + z),
                             (-s + x, -s + y, s + z)
                            ]
            self.edges = [
                          (0,1), (0,3), (0,4), (2,1),
                          (2,3), (2,6), (7,3), (7,4),
                          (7,6), (5,1), (5,4), (5,6)
                         ]
            self.facets = [
                           (0, 1, 2, 3), (0, 1, 6, 5),
                           (0, 3, 7, 4), (6, 5, 1, 2),
                           (6, 7, 4, 5), (6, 7, 3, 2)
                          ]
        def show(self):
            self.render = True
        def hide(self):
            self.render = False

    def keyPressEvent(self, event):    #This is the keypress detector. I use this to determine input to edit grids.
        try:
            key = event.key()
            if key == 87:
                self.rotateV(5)
            elif key == 65:
                self.rotateH(5)
            elif key == 83:
                self.rotateV(-5)
            elif key == 68:
                self.rotateH(-5)
            elif key == 67:
                self.zoom(1)
            elif key == 88:
                self.zoom(-1)
        except:
            pass

    def __init__(self):
        super(mainWindow, self).__init__()
        self.width = 700    #Variables used for the setting of the size of everything
        self.height = 600
        self.setGeometry(0, 0, self.width, self.height)    #Set the window size
        self.shapes.append(self.cube())
        self.shapes.append(self.cube())
        self.shapes.append(self.cube())
        self.shapes[0].config(-1, 0, 0, size = 0.5, solid = False)
        self.shapes[1].config(0, 0, 0, size = 0.5, solid = True, color = (1, 0, 0))
        self.shapes[2].config(1, 0, 0, size = 0.5, solid = True, color = (0, 0, 1))

    def setupUI(self):
        self.openGLWidget = QOpenGLWidget(self)    #Create the GLWidget
        self.openGLWidget.setGeometry(0, 0, self.width, self.height)    #Size it the same as the window.
        self.openGLWidget.initializeGL()
        self.openGLWidget.resizeGL(self.width, self.height)    #Resize GL's knowledge of the window to match the physical size?
        self.openGLWidget.paintGL = self.paintGL    #override the default function with my own?


    def zoom(self, value):
        self.zoomLevel += value
        self.openGLWidget.update()

    def rotateV(self, value):
        self.rotateDegreeV += value
        self.openGLWidget.update()

    def rotateH(self, value):
        self.rotateDegreeH += value
        self.openGLWidget.update()

    def paintGL(self):
        glLoadIdentity()
        gluPerspective(45, self.width / self.height, 0.1, 110.0)    #set perspective?
        glTranslatef(0, 0, self.zoomLevel)    #I used -10 instead of -2 in the PyGame version.
        glRotatef(self.rotateDegreeV, 1, 0, 0)    #I used 2 instead of 1 in the PyGame version.
        glRotatef(self.rotateDegreeH, 0, 0, 1)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

        if len(self.shapes) != 0:
            glBegin(GL_LINES)
            for s in self.shapes:
                if s.render and not s.solid:
                    for e in s.edges:
                        for v in e:
                            glVertex3fv(s.vertices[v])
            glEnd()

            glBegin(GL_QUADS)
            for s in self.shapes:
                if s.render and s.solid:
                    for f in s.facets:
                        for v in f:
                            glColor3fv(s.color)
                            glVertex3fv(s.vertices[v])
            glEnd()


app = QApplication([])
window = mainWindow()
window.setupUI()
window.show()
sys.exit(app.exec_())

person AwesomeCronk    schedule 18.02.2020    source источник


Ответы (1)


OpenGL — это механизм состояний. После того, как состояние установлено, оно сохраняется до тех пор, пока не будет изменено снова, даже за рамками кадра. Текущий цвет является глобальным состоянием. Когда вызывается glColor*, задан текущий цвет.
Когда glVertex* < /a>, то с вершиной связываются текущий цвет, координаты нормали и текстуры.

Это означает, что правильный цвет должен быть установлен до указания вершин. Вы пропустили установку атрибута цвета перед рисованием каркасного куба:

class mainWindow(QMainWindow):    #Main class.
    # [...]

    def paintGL(self):
        # [...]

        if len(self.shapes) != 0:
            glBegin(GL_LINES)
            for s in self.shapes:
                glColor3fv(s.color)  # <------------------------
                if s.render and not s.solid:
                    for e in s.edges:
                        for v in e:
                            glVertex3fv(s.vertices[v])
            glEnd()

            glBegin(GL_QUADS)
            for s in self.shapes:
                glColor3fv(s.color)
                if s.render and s.solid:
                    for f in s.facets:
                        for v in f:
                            glVertex3fv(s.vertices[v])
            glEnd()

Обратите внимание, что нет необходимости устанавливать текущий цвет перед каждым вызовом glVertex3fv. Достаточно один раз задать текущий цвет при его изменении. Новый цвет связан со всеми следующими вершинами.

person Rabbid76    schedule 18.02.2020