PyOpenGL 如何选择颜色来绘制每个形状?
Posted
技术标签:
【中文标题】PyOpenGL 如何选择颜色来绘制每个形状?【英文标题】:How does PyOpenGL pick the colors to draw each shape? 【发布时间】:2020-02-18 21:05:47 【问题描述】:我正在进行一个 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_())
【问题讨论】:
【参考方案1】:OpenGL 是一个状态引擎。一旦设置了一个状态,它就会一直保持到它再次改变,甚至超出帧。当前颜色是全局状态。当调用glColor
* 时,设置当前颜色。
当调用glVertex
* 时,当前颜色、法线和纹理坐标与顶点相关联。
这意味着,必须在指定顶点之前设置正确的颜色。在绘制线框立方体之前,您错过了设置颜色属性:
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
之前,不必设置当前颜色。当它被改变时,设置一次当前颜色就足够了。新颜色与以下所有顶点相关联。
【讨论】:
以上是关于PyOpenGL 如何选择颜色来绘制每个形状?的主要内容,如果未能解决你的问题,请参考以下文章