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 的最后一个参数不是缓冲区对象,而是缓冲区对象数据存储中的偏移量。
当您调用 glVertexPointerglColorPointer 时,当前绑定到目标 GL_ARRAY_BUFFER 的缓冲区将关联到固定函数属性。在调用 glVertexPointerglColorPointer:

之前,您需要绑定正确的缓冲区
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)

来自 glVertexPointer

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