PyOpenGL 如何通过 VBO 为元素着色
PyOpenGL how to color elements by VBO
我正在编写 gcode 发件人。我想按线可视化机器工作的路径(并用其他颜色分隔 G00 移动线)。为了渲染元素,我使用了 VBO 并且它工作正常,但我不知道如何为边缘设置单独的颜色。我尝试在一个单独的 rgb 颜色列表中“标记”一个带有 G00 移动的顶点(您很容易猜到,它不能正常工作)。在互联网上找到的所有解决方案都不适用于我的代码。我真的是 OpenGL 的新手,我 运行 没有想法。也许有人可以告诉我一个我看不到的解决方案。非常感谢您的帮助。
我从缓冲区中提取点并建立边的代码:
def get_edges(self):
for x in range(0, len(self.points) - 2):
self.edges.append(x)
self.edges.append(x+1)
self.edges.append(x+1)
self.edges.append(x)
def get_points_from_buffer(self):
is_first_zminmax = True
is_first_fminmax = True
last_motion_mode = None
for command in self.buffer:
if command.find("G") != -1:
last_motion_mode = command[command.find("G"):command.find("G") + 3]
if command.find("F") != -1:
start = command.find("F") + 1
stop = start
while command[stop].isalpha() is False and stop < len(command) - 1 and command[stop] != ";":
stop += 1
if start == stop:
f = int(command[start])
else:
if stop == len(command) - 1:
f = int(command[start:stop+1])
else:
f = int(command[start:stop])
if is_first_fminmax is True:
is_first_fminmax = False
self.FMinMax[0] = f
self.FMinMax[1] = f
elif f < self.FMinMax[0]:
self.FMinMax[0] = f
elif f > self.FMinMax[1]:
self.FMinMax[1] = f
if command.find("X") != -1 or command.find("Y") != -1 or command.find("Z") != -1:
if last_motion_mode == "G00":
self.colors.append((0.25, 1.0, 0.0))
elif last_motion_mode != "G00":
self.colors.append((1.0, 1.0, 1.0))
if command.find("X") != -1:
start = command.find("X") + 1
stop = start
while command[stop].isalpha() is False and stop < len(command) - 1 and command[stop] != ";":
stop += 1
if start == stop:
x = float(command[start])
else:
if stop == len(command) - 1:
x = float(command[start:stop + 1])
else:
x = float(command[start:stop])
elif len(self.points) == 0:
x = 0
else:
x = self.points[len(self.points) - 1][0]
if command.find("Y") != -1:
start = command.find("Y") + 1
stop = start
while command[stop].isalpha() is False and stop < len(command) - 1 and command[stop] != ";":
stop += 1
if start == stop:
y = float(command[start])
else:
if stop == len(command) - 1:
y = float(command[start:stop + 1])
else:
y = float(command[start:stop])
elif len(self.points) == 0:
y = 0
else:
y = self.points[len(self.points) - 1][1]
if command.find("Z") != -1:
z = self.get_z(command)
if last_motion_mode != "G00" and is_first_zminmax is True:
is_first_zminmax = False
self.ZMinMax[0] = z
self.ZMinMax[1] = z
elif last_motion_mode != "G00":
if z < self.ZMinMax[0]:
self.ZMinMax[0] = z
elif z > self.ZMinMax[1]:
self.ZMinMax[1] = z
elif len(self.points) == 0:
z = 0
else:
z = self.points[len(self.points) - 1][2]
p = (x, y, z)
self.points.append(p)
self.is_motion_line.append(True)
else:
self.is_motion_line.append(False)
self.difZ = self.ZMinMax[1] - self.ZMinMax[0]
我的 OpenGL 代码:
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.arrays import vbo
import numpy as np
from PyQt5 import QtOpenGL
class MyOpenGlWidget(QtOpenGL.QGLWidget):
def __init__(self, parent=None):
QtOpenGL.QGLWidget.__init__(self, parent)
def initGeometry(self, points=None, edges=None, colors=None):
if points is not None and edges is not None and colors is not None:
self.points = np.array(points)
self.vertVBO = vbo.VBO(np.reshape(self.points, (1, -1)).astype(np.float32))
self.vertVBO.bind()
# self.colors = np.array(colors)
# self.clrVBO = vbo.VBO(np.reshape(self.colors, (1, -1)).astype(np.float32))
# self.clrVBO.bind()
self.edges = np.array(edges)
else:
self.points = np.array([])
self.vertVBO = vbo.VBO(np.reshape(self.points, (1, -1)).astype(np.float32))
self.vertVBO.bind()
self.colors = np.array([])
self.clrVBO = vbo.VBO(np.reshape(self.colors, (1, -1)).astype(np.float32))
self.clrVBO.bind()
self.edges = np.array([])
def initializeGL(self):
glClearColor(0.0, 0.0, 0.0, 0.0)
glEnable(GL_DEPTH_TEST)
self.initGeometry()
self.rotX = 0.0
self.rotY = 0.0
self.rotZ = 0.0
def resizeGL(self, w, h):
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
aspect = w / float(h)
gluPerspective(45.0, aspect, 1.0, 100.0)
glMatrixMode(GL_MODELVIEW)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
def paintGL(self, coordinates=None):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glPushMatrix()
glTranslate(0.0, 0.0, -50.0)
glScale(0.1, 0.1, 0.1)
glRotate(self.rotX, 1.0, 0.0, 0.0)
glRotate(self.rotY, 0.0, 1.0, 0.0)
glRotate(self.rotZ, 0.0, 0.0, 1.0)
glTranslate(-0.5, -0.5, -0.5)
glEnableClientState(GL_VERTEX_ARRAY)
# glEnableClientState(GL_COLOR_ARRAY)
glVertexPointer(3, GL_FLOAT, 0, self.vertVBO)
# glColorPointer(3, GL_FLOAT, 0, self.clrVBO)
glDrawElements(GL_QUADS, len(self.edges), GL_UNSIGNED_INT, self.edges)
glDisableClientState(GL_VERTEX_ARRAY)
# glDisableClientState(GL_COLOR_ARRAY)
glPopMatrix()
我已经拥有的:
我想要的:
从 OpenGl 文件取消注释代码后得到的结果:
glVertexPointer
and glColorPointer
的最后一个参数不是缓冲区对象,而是缓冲区对象数据存储中的偏移量。
当您调用 glVertexPointer
或 glColorPointer
时,当前绑定到目标 GL_ARRAY_BUFFER
的缓冲区将关联到固定函数属性。在调用 glVertexPointer
或 glColorPointer
:
之前,您需要绑定正确的缓冲区
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_COLOR_ARRAY)
self.vertVBO.bind()
glVertexPointer(3, GL_FLOAT, 0, None)
self.clrVBO.bind()
glColorPointer(3, GL_FLOAT, 0, None)
的 OpenGL 规范
If a non-zero named buffer object is bound to the GL_ARRAY_BUFFER target (see glBindBuffer) while a vertex array is specified, pointer is treated as a byte offset into the buffer object's data store.
本质上这意味着 glVertexPointer
的最后一个参数指定了最后一个绑定缓冲区的偏移量,而不是实际缓冲区本身。
因此,为了纠正此问题,您需要绑定 vertVBO
并指定 glVertexPointer
,然后绑定 clrVBO
并指定 glColorPointer
。这让 OpenGL 知道有两个缓冲区有不同的数据。
示例:
self.vertVBO.bind()
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, G_FLOAT, 0, None)
self.clrVBO.bind()
glEnableClientState(GL_COLOR_ARRAY)
glColorPointer(3, GL_FLOAT, 0, None)
我正在编写 gcode 发件人。我想按线可视化机器工作的路径(并用其他颜色分隔 G00 移动线)。为了渲染元素,我使用了 VBO 并且它工作正常,但我不知道如何为边缘设置单独的颜色。我尝试在一个单独的 rgb 颜色列表中“标记”一个带有 G00 移动的顶点(您很容易猜到,它不能正常工作)。在互联网上找到的所有解决方案都不适用于我的代码。我真的是 OpenGL 的新手,我 运行 没有想法。也许有人可以告诉我一个我看不到的解决方案。非常感谢您的帮助。
我从缓冲区中提取点并建立边的代码:
def get_edges(self):
for x in range(0, len(self.points) - 2):
self.edges.append(x)
self.edges.append(x+1)
self.edges.append(x+1)
self.edges.append(x)
def get_points_from_buffer(self):
is_first_zminmax = True
is_first_fminmax = True
last_motion_mode = None
for command in self.buffer:
if command.find("G") != -1:
last_motion_mode = command[command.find("G"):command.find("G") + 3]
if command.find("F") != -1:
start = command.find("F") + 1
stop = start
while command[stop].isalpha() is False and stop < len(command) - 1 and command[stop] != ";":
stop += 1
if start == stop:
f = int(command[start])
else:
if stop == len(command) - 1:
f = int(command[start:stop+1])
else:
f = int(command[start:stop])
if is_first_fminmax is True:
is_first_fminmax = False
self.FMinMax[0] = f
self.FMinMax[1] = f
elif f < self.FMinMax[0]:
self.FMinMax[0] = f
elif f > self.FMinMax[1]:
self.FMinMax[1] = f
if command.find("X") != -1 or command.find("Y") != -1 or command.find("Z") != -1:
if last_motion_mode == "G00":
self.colors.append((0.25, 1.0, 0.0))
elif last_motion_mode != "G00":
self.colors.append((1.0, 1.0, 1.0))
if command.find("X") != -1:
start = command.find("X") + 1
stop = start
while command[stop].isalpha() is False and stop < len(command) - 1 and command[stop] != ";":
stop += 1
if start == stop:
x = float(command[start])
else:
if stop == len(command) - 1:
x = float(command[start:stop + 1])
else:
x = float(command[start:stop])
elif len(self.points) == 0:
x = 0
else:
x = self.points[len(self.points) - 1][0]
if command.find("Y") != -1:
start = command.find("Y") + 1
stop = start
while command[stop].isalpha() is False and stop < len(command) - 1 and command[stop] != ";":
stop += 1
if start == stop:
y = float(command[start])
else:
if stop == len(command) - 1:
y = float(command[start:stop + 1])
else:
y = float(command[start:stop])
elif len(self.points) == 0:
y = 0
else:
y = self.points[len(self.points) - 1][1]
if command.find("Z") != -1:
z = self.get_z(command)
if last_motion_mode != "G00" and is_first_zminmax is True:
is_first_zminmax = False
self.ZMinMax[0] = z
self.ZMinMax[1] = z
elif last_motion_mode != "G00":
if z < self.ZMinMax[0]:
self.ZMinMax[0] = z
elif z > self.ZMinMax[1]:
self.ZMinMax[1] = z
elif len(self.points) == 0:
z = 0
else:
z = self.points[len(self.points) - 1][2]
p = (x, y, z)
self.points.append(p)
self.is_motion_line.append(True)
else:
self.is_motion_line.append(False)
self.difZ = self.ZMinMax[1] - self.ZMinMax[0]
我的 OpenGL 代码:
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.arrays import vbo
import numpy as np
from PyQt5 import QtOpenGL
class MyOpenGlWidget(QtOpenGL.QGLWidget):
def __init__(self, parent=None):
QtOpenGL.QGLWidget.__init__(self, parent)
def initGeometry(self, points=None, edges=None, colors=None):
if points is not None and edges is not None and colors is not None:
self.points = np.array(points)
self.vertVBO = vbo.VBO(np.reshape(self.points, (1, -1)).astype(np.float32))
self.vertVBO.bind()
# self.colors = np.array(colors)
# self.clrVBO = vbo.VBO(np.reshape(self.colors, (1, -1)).astype(np.float32))
# self.clrVBO.bind()
self.edges = np.array(edges)
else:
self.points = np.array([])
self.vertVBO = vbo.VBO(np.reshape(self.points, (1, -1)).astype(np.float32))
self.vertVBO.bind()
self.colors = np.array([])
self.clrVBO = vbo.VBO(np.reshape(self.colors, (1, -1)).astype(np.float32))
self.clrVBO.bind()
self.edges = np.array([])
def initializeGL(self):
glClearColor(0.0, 0.0, 0.0, 0.0)
glEnable(GL_DEPTH_TEST)
self.initGeometry()
self.rotX = 0.0
self.rotY = 0.0
self.rotZ = 0.0
def resizeGL(self, w, h):
glViewport(0, 0, w, h)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
aspect = w / float(h)
gluPerspective(45.0, aspect, 1.0, 100.0)
glMatrixMode(GL_MODELVIEW)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
def paintGL(self, coordinates=None):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glPushMatrix()
glTranslate(0.0, 0.0, -50.0)
glScale(0.1, 0.1, 0.1)
glRotate(self.rotX, 1.0, 0.0, 0.0)
glRotate(self.rotY, 0.0, 1.0, 0.0)
glRotate(self.rotZ, 0.0, 0.0, 1.0)
glTranslate(-0.5, -0.5, -0.5)
glEnableClientState(GL_VERTEX_ARRAY)
# glEnableClientState(GL_COLOR_ARRAY)
glVertexPointer(3, GL_FLOAT, 0, self.vertVBO)
# glColorPointer(3, GL_FLOAT, 0, self.clrVBO)
glDrawElements(GL_QUADS, len(self.edges), GL_UNSIGNED_INT, self.edges)
glDisableClientState(GL_VERTEX_ARRAY)
# glDisableClientState(GL_COLOR_ARRAY)
glPopMatrix()
我已经拥有的:
我想要的:
从 OpenGl 文件取消注释代码后得到的结果:
glVertexPointer
and glColorPointer
的最后一个参数不是缓冲区对象,而是缓冲区对象数据存储中的偏移量。
当您调用 glVertexPointer
或 glColorPointer
时,当前绑定到目标 GL_ARRAY_BUFFER
的缓冲区将关联到固定函数属性。在调用 glVertexPointer
或 glColorPointer
:
glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_COLOR_ARRAY)
self.vertVBO.bind()
glVertexPointer(3, GL_FLOAT, 0, None)
self.clrVBO.bind()
glColorPointer(3, GL_FLOAT, 0, None)
If a non-zero named buffer object is bound to the GL_ARRAY_BUFFER target (see glBindBuffer) while a vertex array is specified, pointer is treated as a byte offset into the buffer object's data store.
本质上这意味着 glVertexPointer
的最后一个参数指定了最后一个绑定缓冲区的偏移量,而不是实际缓冲区本身。
因此,为了纠正此问题,您需要绑定 vertVBO
并指定 glVertexPointer
,然后绑定 clrVBO
并指定 glColorPointer
。这让 OpenGL 知道有两个缓冲区有不同的数据。
示例:
self.vertVBO.bind()
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, G_FLOAT, 0, None)
self.clrVBO.bind()
glEnableClientState(GL_COLOR_ARRAY)
glColorPointer(3, GL_FLOAT, 0, None)