为什么要删除PyOpenGL渲染形状?

问题描述 投票:0回答:1

我正在使用PyQt5和PyOpenGL实现行进立方体算法。我终于可以使用下面的代码进行行进,绘制点并绘制网格。唯一的问题是,当它循环返回时,将绘制上一个循环的网格。即使过滤器已更改,仍会绘制原始网格。

我在做什么错?

cubes.py:

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
from numerics import sin, cos, tan, avg, rnd
from classes import *
from lookup import table
import random, time

class mainWindow(QMainWindow):    #Main class.
    shapes = []    #place all instaces of shapes in this list in order to have them rendered.
    dataPoints = []
    zoomLevel = -10
    rotateDegreeV = -90
    rotateDegreeH = 0
    marchActive = False
    limit = -1
    meshPoints = []
    meshSectors = []

    def keyPressEvent(self, event):    #This is the keypress detector.
        try:
            key = event.key()
        except:
            key = -1    
        #print(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)
        elif key == 77:
            self.marchStep()

    def __init__(self):
        super(mainWindow, self).__init__()
        self.currentStep = 0
        self.width = 700    #Variables used for the setting of the size of everything
        self.height = 600
        self.setGeometry(0, 0, self.width + 50, self.height)    #Set the window size
        self.initData(3, 3, 3)

    def setupUI(self):
        self.openGLWidget = QOpenGLWidget(self)    #Create the GLWidget
        self.openGLWidget.setGeometry(0, 0, self.width, self.height)
        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?

        self.filterSlider = QSlider(Qt.Vertical, self)
        self.filterSlider.setGeometry(self.width + 10, int(self.height / 2) - 100, 30, 200)
        self.filterSlider.valueChanged[int].connect(self.filter)

        self.limitDisplay = QLabel(self)
        self.limitDisplay.setGeometry(self.width, int(self.height / 2) - 130, 50, 30)
        self.limitDisplay.setAlignment(Qt.AlignCenter)
        self.limitDisplay.setText('-1')

        self.marchButton = QPushButton(self)
        self.marchButton.setGeometry(self.width, int(self.height / 2) - 160, 50, 30)
        self.marchButton.setText('March!')
        self.marchButton.clicked.connect(self.marchStep)

    def initData(self, sizeX, sizeY, sizeZ):
        marchSizeX = sizeX - 1
        marchSizeY = sizeY - 1
        marchSizeZ = sizeZ - 1
        xOff = -(sizeX / 2) + 0.5
        yOff = -(sizeY / 2) + 0.5
        zOff = -(sizeZ / 2) + 0.5
        xMarchOff = -(marchSizeX / 2) + 0.5
        yMarchOff = -(marchSizeY / 2) + 0.5
        zMarchOff = -(marchSizeZ / 2) + 0.5
        self.marchPoints = []
        for z in range(marchSizeZ):
            for y in range(marchSizeY):
                for x in range(marchSizeX):
                    self.marchPoints.append((x + xMarchOff, y + yMarchOff ,z + zMarchOff))

        for z in range(sizeZ):
            for y in range(sizeY):
                for x in range(sizeX):
                    val = self.generate(x + xOff, y + yOff, z + zOff)
                    dpColor = (0, (val + 1) / 2, (val + 1) / -2 + 1)
                    dpShape = cube((x + xOff, y + yOff, z + zOff), drawWires = False, drawFaces = True, color = dpColor)
                    dp = dataPoint((x + xOff, y + yOff, z + zOff), val, dpShape)
                    self.dataPoints.append(dp)
                    self.shapes.append(dpShape)

    def paintGL(self):
        #This function uses shape objects, such as cube() or meshSector(). Shape objects require the following:
        #a list named 'vertices' - This list is a list of points, from which edges and faces are drawn.
        #a list named 'wires'    - This list is a list of tuples which refer to vertices, dictating where to draw wires.
        #a list named 'facets'   - This list is a list of tuples which refer to vertices, ditating where to draw facets.
        #a bool named 'render'   - This bool is used to dictate whether or not to draw the shape.
        #a bool named 'drawWires' - This bool is used to dictate whether wires should be drawn.
        #a bool named 'drawFaces' - This bool is used to dictate whether facets should be drawn.

        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:
                glColor3fv(s.color)
                if s.render and s.drawWires:
                    for w in s.wires:
                        for v in w:
                            glVertex3fv(s.vertices[v])
            glEnd()

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

    def marchStep(self):
        print(self.currentStep)
        if not self.marchActive:    #initialize
            marchAddr = len(self.shapes)
            self.marchingCube = cube(size = 1)
            self.shapes.append(self.marchingCube)
            self.marchActive = True
            self.currentStep = 0

        if self.currentStep == len(self.marchPoints):    #1 step after last
            self.marchingCube.hide()
            self.currentStep += 1
            for mp in self.meshPoints:
                mp.shape.hide()
            self.meshPoints = []
            self.openGLWidget.update()
            return
        if self.currentStep == len(self.marchPoints) + 1:    #2 steps after last
            #print('meshPoints: {}'.format(self.meshPoints))
            for mp in self.meshPoints:
                #print(mp.shape)
                self.shapes.remove(mp.shape)
            self.meshPoints.clear()
            for shape in self.shapes:
                if shape in self.meshSectors:
                    self.shapes.remove(shape)
            self.meshSectors = []
            self.currentStep = -1
            self.openGLWidget.update()
            return

        if self.currentStep == -1:    #1 step before first
            self.marchingCube.hide()
            self.currentStep += 1
            print('self.meshPoints: {}\nself.meshSectors: {}\nself.shapes: {}'.format(self.meshPoints, self.meshSectors, self.shapes))
            self.openGLWidget.update()
            return

        self.marchingCube.show()
        p = self.marchPoints[self.currentStep]
        x, y, z = p
        self.marchingCube.move((x, y, z))
        points = []
        for i in range(8):
            #print(self.marchingCube.vertices[i])
            point = self.getDataPointByLocation(self.marchingCube.vertices[i])
            points.append(point)

        #place meshpoints and highlight the active ones.
        MPs = []
        for pair in self.marchingCube.wires:
            pointA = points[pair[0]]
            pointB = points[pair[1]]
            #print('pointA.value: {}  pointB.value: {}  limit: {}'.formatpointA.value, pointB.value, self.limit)
            xA, yA, zA = pointA.location
            xB, yB, zB = pointB.location
            valA = (pointA.value + 1) / 2
            valB = (pointB.value + 1) / 2
            xC = float(avg([xA, xB]))
            yC = float(avg([yA, yB]))
            zC = float(avg([zA, zB]))

            mp = meshPoint()
            mp.place(xC, yC, zC)
            mp.setShape(cube(size = 0.05, drawWires = False, drawFaces = True, color = (1, 0, 0)))
            mp.shape.move((xC, yC, zC))
            self.shapes.append(mp.shape)
            self.meshPoints.append(mp)
            MPs.append(mp)
            if (pointA.value < self.limit and pointB.value > self.limit) or (pointA.value > self.limit and pointB.value < self.limit):
                mp.setActive(True)
            else:
                mp.setActive(False)

        activeConfig = 0
        sector = meshSector()
        self.meshSectors.append(sector)
        self.shapes.append(sector)

        for i in range(8):
            if points[i].value > self.limit:
                activeConfig += int(2 ** i)
        print('Configuration number: {}'.format(activeConfig))
        if activeConfig > 127:
            activeConfig = 255 - activeConfig
        print('Configuration number: {}'.format(activeConfig))

        config = table[activeConfig]
        print('Configuration: {}'.format(config))
        print('number of points: {}'.format(len(MPs)))
        for data in config:
            a, b, c = data
            locA = MPs[a].location
            locB = MPs[b].location
            locC = MPs[c].location
            sector.addFacet((locA, locB, locC))

        print('stepping')
        self.currentStep += 1
        self.rotateH(0)

    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 filter(self, value):
        self.limit = rnd((value / 49.5) -1, -2)
        for d in self.dataPoints:
            if d.value < self.limit:
                d.shape.hide()
            else:
                d.shape.show()
        self.limitDisplay.setText(str(self.limit))
        self.openGLWidget.update()

    def getDataPointByLocation(self, coord):
        x, y, z = coord
        #print(self.dataPoints)
        #print('requested coordinates: {}'.format(coord))
        for dp in self.dataPoints:
            #print('dataPoint.location: {}'.format(dp.location))
            if dp.location == (x, y, z):
                return dp
        return False

    def generate2(self, xIn, yIn, zIn):
        if xIn == 0 and yIn == 0 and zIn == 0:
            return 0.5
        return -0.5

    def generate(self, xIn, yIn, zIn):    #Function which produces semi-random values based on the supplied coordinates.
        i = -int(xIn * yIn * (10 + zIn))
        j = int(xIn * yIn * (10 + zIn))
        if i < j:
            mixer = random.randint(i, j + 1)
        else:
            mixer = random.randint(j, i + 1)
        a = avg([sin(cos(xIn)), tan(tan(yIn)), cos(tan(zIn))])
        out = mixer * a
        while out > 10:
            out -= 5
        while out < -10:
            out += 5
        return float(out / 10)

    #classes------------------------------------------------------------


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

classes.py:

class cube():
    render = True
    def __init__(self, location = (0, 0, 0), size = 0.1, drawWires = True, drawFaces = False, color = (1, 1, 1)):
        self.location = location
        self.size = size
        self.drawWires = drawWires
        self.drawFaces = drawFaces
        self.color = color
        self.compute()

    def compute(self):
        x, y, z = self.location
        s = self.size / 2
        self.vertices = [    #8 corner points calculated in reference to the supplied center point
                         (-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.wires = [    #12 tuples referencing the corner points
                      (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 = [    #6 tuples referencing the corner points
                       (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 move(self, location):
        self.location = location
        self.compute()
    def recolor(self, col):
        if type(col) is tuple:
            self.color = col

class dataPoint():
    def __init__(self, location = (0, 0, 0), value = 0, shape = None):
        self.location = location
        self.value = value
        self.shape = shape
    def place(self, x, y, z):
        self.location = (x, y, z)
    def set(self, val):
        self.value = val
    def setShape(self, shape):
        self.shape = shape

class meshPoint():
    active = False
    def __init__(self, location = (0, 0, 0), shape = None):
        self.location = location
        self.shape = shape
        if self.shape != None:
            #print('{} is hiding shape'.format(self))
            self.shape.hide()
    def place(self, x, y, z):
        self.location = (x, y, z)
    def setShape(self, shape):
        self.shape = shape
        if self.shape != None:
            #print('{} is hiding shape'.format(self))
            self.shape.hide()
    def setActive(self, state):
        self.active = state
        if self.active and self.shape != None:
            #print('{} is showing shape'.format(self))
            self.shape.show()
        elif self.shape != None:
            #print('{} is hiding shape'.format(self))
            self.shape.hide()

class meshSector():
    vertices = []
    facets = []
    wires = []
    render = True
    def __init__(self, drawWires = True, drawFaces = False, color = (1, 1, 1)):
        self.drawWires = drawWires
        self.drawFaces = drawFaces
        self.color = color
    def addFacet(self, coords):    #takes a tuple of three location tuples.
        addr = len(self.vertices)
        for c in coords:
            self.vertices.append(c)
        self.facets.append((addr, addr + 1, addr + 2))
        self.wires.append((addr, addr + 1))
        self.wires.append((addr, addr + 2))
        self.wires.append((addr + 1, addr + 2))


lookup.py:

table = [    #config number is line number - 2
[],    #config 0
[(0, 1, 2)],
[(0, 3, 9)],
[(1, 2, 3), (2, 3, 9)],
[(3, 4, 5)],
[(0, 1, 2), (3, 4, 5)],
[(0, 4, 5), (0, 5, 9)],
[(1, 2, 9), (1, 4, 9), (4, 5, 9)],
[(1, 4, 6)],
[(0, 2, 4), (0, 2, 6)],
[(0, 3, 9), (1, 4, 6)],    #config 10
[(2, 3, 4), (2, 3, 9), (2, 4, 6)],
[(1, 3, 5), (1, 5, 6)],
[(0, 2, 6), (0, 3, 6), (3, 5, 6)],
[(0, 1, 5), (0, 5, 9), (1, 5, 6)],
[(2, 5, 6), (2, 5, 9)],
[(2, 7, 10)],
[(0, 1, 7), (0, 7, 10)],
[(2, 7, 10), (0, 3, 9)],
[(1, 3, 9), (1, 7, 10), (1, 9, 10)],
[(2, 6, 10), (3, 4, 5)],    #config 20
[(0, 1, 7), (0, 1, 10), (3, 4, 5)],
[(0, 4, 5), (0, 5, 9), (2, 7, 10)],
[(1, 7, 10), (1, 9, 10), (1, 5, 9), (1, 4, 5)],
[(1, 4, 6), (2, 7, 10)],
[(0, 4, 6), (0, 6, 7), (0, 7, 10)],
[(0, 3, 9), (1, 4, 6), (2, 7, 10)],
[(6, 7, 10), (3, 9, 10), (3, 4, 6)],
[(1, 3, 5), (1, 5, 6), (2, 7, 10)],
[(0, 7, 10), (0, 6, 7), (0, 5, 6), (0, 3, 5)],
[(0, 1, 2), (5, 6, 7), (5, 7, 10), (5, 9, 10)],    #config 30
[(5, 6, 7), (5, 7, 10), (5, 9, 10)],
[(9, 10, 11)],
[(0, 1, 2), (9, 10, 11)],
[(0, 3, 10), (3, 10, 11)],
[(1, 2, 3), (2, 3, 10), (3, 10, 11)],
[(3, 4, 5), (9, 10, 11)],
[(0, 1, 2), (3, 4, 5), (9, 10, 11)],
[(0, 4, 5), (0, 5, 11), (0, 10, 11)],
[(2, 10, 11), (4, 5, 11), (1, 2, 4), (2, 4, 11)],
[(1, 4, 6), (9, 10, 11)],    #config 40
[(0, 2, 4), (2, 4, 6), (9, 10, 11)],
[(0, 3, 10), (3, 10, 11), (1, 4, 6)],
[(2, 4, 6), (2, 3, 4), (2, 3, 11), (2, 10, 11)],
[(1, 3, 5), (1, 5, 6), (9, 10, 11)],
[(3, 5, 6), (0, 3, 6), (0, 2, 6), (9, 10, 11)],
[(0, 1, 6), (0, 5, 6), (0, 5, 11), (0, 10, 11)],
[(5, 6, 11), (6, 10, 11), (2, 6, 10)],
[(2, 7, 9), (7, 9, 11)],
[(0, 1, 7), (0, 7, 9), (7, 9, 11)],
[(0, 3, 11), (0, 2, 11), (2, 7, 11)],    #config 50
[(1, 3, 11), (1, 7, 11)],
[(2, 9, 11), (1, 7, 11), (3, 4, 5)],
[(7, 9, 11), (0, 7, 9), (0, 1, 7), (3, 4, 5)],
[(2, 7, 11), (0, 2, 11), (0, 4, 11), (0, 5, 11)],
[(1, 4, 7), (1, 5, 7), (5, 7, 11)],
[(2, 7, 9), (7, 9, 11), (1, 4, 6)],
[(4, 6, 7), (0, 4, 7), (0, 7, 11), (0, 9, 11)],
[(1, 4, 6), (2, 7, 11), (0, 2, 11), (0, 3, 11)],
[(3, 7, 11), (3, 6, 7), (3, 4, 6)],
[(2, 7, 11), (2, 9, 11), (1, 3, 5), (1, 5, 6)],    #config 60
[(0, 9, 11), (0, 7, 11), (0, 6, 7), (0, 3, 6), (3, 5, 6)],
[(2, 7, 11), (0, 2, 11), (0, 5, 11), (0, 1, 5), (1, 5, 6)],
[(5, 6, 7), (5, 7, 11)],
[(5, 8, 11)],
[(0, 1, 2), (5, 8, 11)],
[(0, 3, 9), (5, 8, 11)],
[(1, 2, 3), (2, 3, 9), (5, 8, 11)],
[(3, 4, 8), (3, 8, 11)],
[(3, 4, 8), (3, 8, 11), (0, 1, 2)],
[(0, 9, 11), (0, 8, 11), (0, 4, 8)],    #config 70
[(2, 10, 11), (2, 3, 11), (2, 3, 4), (2, 4, 6)],
[(3, 4, 5), (9, 10, 11)],
[(1, 3, 5), (1, 5, 6), (9, 10, 11)],
[(0, 1, 2), (3, 4 ,5), (9, 10, 11)],
[(2, 3, 9), (2, 3, 4), (2, 4, 6), (5, 8, 11)],
[(3, 1, 6), (3, 6, 8), (3, 8, 11)],
[(7, 9, 10), (5, 7, 9), (1, 5, 7), (1, 4, 5)],
[(6, 7, 10), (3, 9, 10), (3, 4, 6), (3, 6, 10)],
[(6, 8, 11), (6, 9, 11), (2, 6, 9)],
[(2, 7, 10), (5, 8, 11)],    #config 80
[(0, 1, 7), (0, 7, 10), (5, 8, 11)],
[(0, 3, 9), (2, 7, 10), (5, 8, 11)],
[(1, 7, 10), (1, 9, 10), (1, 3, 9), (5, 8, 11)],
[(3, 4, 8), (3, 8, 11), (2, 7, 10)],
[(0, 1, 7), (0, 7, 10), (3, 4, 8), (3, 8, 11)],
[(4, 8, 11), (4, 9, 11), (0, 4, 9), (2, 7, 10)],
[(9, 10, 11), (1, 4, 7), (4, 7, 8)],
[(1, 4, 6), (2, 7, 10), (5, 8, 11)],
[(0, 4, 6), (0, 6, 7), (0, 7, 10), (5, 8, 11)],
[(0, 3, 9), (1, 4, 6), (5, 8, 11), (2, 7, 10)],    #config 90
[(3, 4, 6), (6, 7, 10), (3, 9, 10), (5, 8, 11)],
[(1, 3, 6), (3, 6, 8), (3, 8, 11), (2, 7, 10)],
[(0, 3, 10), (3, 10, 11), (6, 7, 8)],
[(0, 1, 2), (6, 7, 8), (9, 10, 11)],
[(6, 7, 8), (9, 10, 11)],
[(5, 8, 9), (8, 9, 10)],
[(0, 1, 2), (5, 8, 9), (8, 9, 10)],
[(0, 8, 10), (0, 3, 8), (3, 5, 8)],
[(2, 8, 10), (1, 2, 8), (1, 5, 8), (1, 3, 5)],
[(3, 4, 8), (3, 8, 9), (8, 9, 10)],    #config 100
[(0, 1, 2), (3, 4, 8), (3, 8, 9), (8, 9, 10)],
[(0, 4, 8), (0, 8, 10)],
[(1, 4, 8), (1, 2, 8), (2, 8, 10)],
[(1, 4, 6), (5, 8, 9), (8, 9, 10)],
[(0, 4, 6), (0, 2, 6), (5, 8, 9), (8, 9, 10)],
[(1, 4, 6), (0, 8, 10), (0, 3, 5), (1, 4, 6)],
[(3, 4, 5), (2, 6, 8), (2, 8, 10)],
[(1, 6, 8), (1, 3, 8), (3, 8, 10), (3, 9, 10)],
[(0, 3, 9), (2, 6, 8), (2, 8, 10)],
[(0, 1, 10), (1, 6, 10), (6, 8, 10)],    #config 110
[(2, 6, 8), (2, 8, 10)],
[(2, 5, 9), (2, 5, 8), (2, 7, 8)],
[(0, 5, 9), (0, 5, 8), (0, 1, 8), (1, 7, 8)],
[(0, 3, 5), (5, 7, 8), (0, 2, 7), (0, 5, 7)],
[(1, 3, 5), (1, 5, 8), (1, 7, 8)],
[(3, 4, 9), (4, 7, 9), (2, 7, 9), (4, 7, 8)],
[(0, 3, 9), (1, 4, 8), (1, 7, 8)],
[(0, 4, 8), (0, 7, 8), (0, 2, 7)],
[(1, 4, 7), (4, 7, 8)],
[(2, 5, 9), (1, 2, 4), (2, 4, 5), (6, 7, 8)],    #config 120
[(6, 7, 8), (0, 4, 5), (0, 5, 9)],
[(0, 3, 5), (5, 7, 8), (0, 2, 7), (0, 5, 7), (1, 4, 6)],
[(3, 5, 8), (5, 7, 8), (3, 4, 7), (4, 6, 7)],
[(1, 2, 3), (2, 3, 9), (6, 7, 8)],
[(0, 3, 9), (6, 7, 8)],
[(0, 1, 2), (6, 7, 8)],
[(6, 7, 8)]
]

run.bat:

@echo off
cls
cubes.py

这可能是我做过的最大的编码项目。

python pyopengl
1个回答
0
投票

我发现了问题。由于某种原因,每当我实例化一个新的meshSector时,最后一个实例中的值就会被继承。我不明白为什么会这样,但是我的解决方法是清空__init__函数中的变量。]​​>

class meshSector():
    vertices = []
    facets = []
    wires = []
    render = True
    def __init__(self, drawWires = True, drawFaces = False, color = (1, 1, 1)):
        self.drawWires = drawWires
        self.drawFaces = drawFaces
        self.color = color
        #the next four lines prevent data carry-over.
        self.vertices = []
        self.facets = []
        self.wires = []
        self.render = True
    def addFacet(self, coords):    #takes a tuple of three location tuples.
        addr = len(self.vertices)
        for c in coords:
            self.vertices.append(c)
        self.facets.append((addr, addr + 1, addr + 2))
        self.wires.append((addr, addr + 1))
        self.wires.append((addr, addr + 2))
        self.wires.append((addr + 1, addr + 2))
© www.soinside.com 2019 - 2024. All rights reserved.