OpenGL - Stapelüberlauf, wenn ich es tue, Stapelunterlauf, wenn ich es nicht tue!

7

Ich bin in einer Multimedia-Klasse im College und wir "lernen" OpenGL als Teil der Klasse. Ich versuche herauszufinden, wie die OpenGL-Kamera im Vergleich zur Modellansicht funktioniert, und habe dieses Beispiel gefunden. Ich versuche, das Beispiel mithilfe der OpenGL-Bindungen auf Python zu portieren - es startet OpenGL viel schneller, daher ist es zu Testzwecken viel besser -, aber ich stoße immer wieder auf einen Stapelüberlauffehler mit der glPushMatrix in diesem Code:

  def cube(): 
      for x in xrange(10):
          glPushMatrix()
          glTranslated(-positionx[x + 1] * 10, 0, -positionz[x + 1] * 10); #translate the cube
          glutSolidCube(2); #draw the cube
          glPopMatrix();

Nach dieser Referenz geschieht dies, wenn der Matrixstapel voll ist.

Also dachte ich: "Nun, wenn es voll ist, lass mich einfach die Matrix von der Oberseite des Stapels entfernen, und es wird Platz geben." Ich habe den Code geändert in:

  def cube(): 
      glPopMatrix()
      for x in xrange(10):
          glPushMatrix()
          glTranslated(-positionx[x + 1] * 10, 0, -positionz[x + 1] * 10); #translate the cube
          glutSolidCube(2); #draw the cube
          glPopMatrix();

Und jetzt erhalte ich einen Pufferunterlauffehler - der anscheinend auftritt, wenn der Stapel nur eine Matrix hat.

Also bin ich in meinem Verständnis nur von der Basis abgekommen? Oder gibt es eine Möglichkeit, die Größe des Matrixstapels zu erhöhen?

Wenn jemand gute (Online-) Referenzen (Beispiele usw.) hat, um zu verstehen, wie die Kamera- / Modellmatrizen zusammenarbeiten, würde ich sie aufrichtig schätzen!

Vielen Dank!

BEARBEITEN:

Hier ist der Pastebin des vollständigen Codes: http://pastebin.com/QXxNisuA

Wayne Werner
quelle
2
Ist das dein gesamter Code? Sind Sie sicher, dass Sie keine glPushMatrix mehr ausführen, die keine entsprechende glPopMatrix hat? Sind Sie sicher, dass das for nicht nur die glPushMatrix-Anweisung betrifft?
r2d2rigo
Ja, wir müssen Ihren anderen Code sehen. Wo richten Sie die Projektionsmatrix ein? Sind Sie schon in den GL_MODELVIEW-Modus gewechselt? (Der Projektionsmatrixstapel ist unglaublich klein.)
TheBuzzSaw
Vermeiden Sie auf jeden Fall Ihr zweites Codebeispiel. Wenn eine glPopMatrix nur ohne entsprechende glPushMatrix dort schwebt, würde dies sicherlich zu einem Unterlauf führen. Ihr erstes Codebeispiel sieht in Ordnung aus. Der Rest Ihres Codes muss ein Problem enthalten.
TheBuzzSaw
Ich habe meine Antwort gelöscht, weil sie einen Fehler enthielt. Ich nahm etwas an, was nicht stimmte.
Notabene
1
Warum fragst du das nicht bei Stack'Flow ?
Mateen Ulhaq

Antworten:

9

Bearbeitet, um hinzuzufügen: Dies ist vorerst nicht wichtig, da es immer noch gut funktioniert und das Erlernen von OpenGL erleichtert. Beachten Sie jedoch, dass das gesamte Matrix-Stack-System in OpenGL 3.x und darüber hinaus veraltet ist. Ein möglicher Ersatz ist GLM .

Der Code in Ihrem Pastebin läuft nicht einmal für mich.

Insbesondere liegen Ihre Listenindizes in der Anzeigefunktion außerhalb des Bereichs (Ihre Liste enthält 10 Elemente: Python-Listen beginnen bei 0; Sie indizieren von 0 + 1 bis 10 + 1).

Ich denke, Sie hatten auch einige Globals in der Maushandhabungsfunktion vermisst, aber das könnte daran liegen, dass ich Code verschiebe, um ihn zumindest wie Python aussehen zu lassen;)

Wie auch immer, mit diesen Korrekturen funktioniert der unten gezeigte Code für mich, ohne Anzeichen eines Unter- / Überlaufs des GL-Matrixstapels!

import sys
from math import sin, cos
from random import randint
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
#angle of rotation
xpos= ypos= zpos= xrot= yrot= angle= lastx= lasty = 0

#positions of the cubes
positionz = []
positionx = []

def init():
    global positionz, positionx
    glEnable(GL_DEPTH_TEST) #enable the depth testing
    glEnable(GL_LIGHTING) #enable the lighting
    glEnable(GL_LIGHT0) #enable LIGHT0, our Diffuse Light
    glShadeModel(GL_SMOOTH) #set the shader to smooth shader

    positionx = [randint(0, 10) for x in xrange(10)]
    positionz = [randint(0, 10) for x in xrange(10)]

def camera():
    global xrot, yrot, xpos, ypos, zpos
    glRotatef(xrot,1.0,0.0,0.0)  #rotate our camera on teh x-axis (left and right)
    glRotatef(yrot,0.0,1.0,0.0)  #rotate our camera on the y-axis (up and down)
    glTranslated(-xpos,-ypos,-zpos) #translate the screen to the position of our camera

def display():
    global angle
    glClearColor(0.0,0.0,0.0,1.0) #clear the screen to black
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) #clear the color buffer and the depth buffer
    glLoadIdentity()
    camera()
    for x in xrange(10):
        glPushMatrix()
        glTranslated(-positionx[x] * 10, 0, -positionz[x] * 10) #translate the cube
        glutSolidCube(2) #draw the cube
        glPopMatrix()
    glutSwapBuffers() #swap the buffers
    angle += angle #increase the angle

def reshape(w, h):
    glViewport(0, 0, w, h); #set the viewport to the current window specifications
    glMatrixMode(GL_PROJECTION); #set the matrix to projection

    glLoadIdentity();
    gluPerspective(60, w / h, 1.0, 1000.0)
    #set the perspective (angle of sight, width, height, , depth)
    glMatrixMode(GL_MODELVIEW); #set the matrix back to model

def keyboard (key, x, y):
    global xrot, xpos, ypos, zpos, xrot, yrot, angle, lastx, lasty, positionz, positionx
    if (key=='q'):
        xrot += 1
        if (xrot >360):
            xrot -= 360
    if (key=='z'):
        xrot -= 1;
        if (xrot < -360): xrot += 360
    if (key=='w'):
        yrotrad = (yrot / 180 * 3.141592654)
        xrotrad = (xrot / 180 * 3.141592654)
        xpos += float(sin(yrotrad))
        zpos -= float(cos(yrotrad))
        ypos -= float(sin(xrotrad))
    if (key=='s'):
        yrotrad = (yrot / 180 * 3.141592654)
        xrotrad = (xrot / 180 * 3.141592654)
        xpos -= float(sin(yrotrad))
        zpos += float(cos(yrotrad))
        ypos += float(sin(xrotrad))
    if (key=='d'):
        yrotrad = (yrot / 180 * 3.141592654)
        xpos += float(cos(yrotrad)) * 0.2
        zpos += float(sin(yrotrad)) * 0.2
    if (key=='a'):
        yrotrad = (yrot / 180 * 3.141592654)
        xpos -= float(cos(yrotrad)) * 0.2
        zpos -= float(sin(yrotrad)) * 0.2
    if (key==27):
        sys.exit(0)

def mouseMovement(x, y):
    global lastx, lasty, xrot, yrot
    diffx=x-lastx #check the difference between the current x and the last x position
    diffy=y-lasty #check the difference between the current y and the last y position
    lastx=x #set lastx to the current x position
    lasty=y #set lasty to the current y position
    xrot += float(diffy) #set the xrot to xrot with the addition of the difference in the y position
    yrot += float(diffx) #set the xrot to yrot with the addition of the difference in the x position

glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH)
glutInitWindowSize(500, 500)
glutInitWindowPosition (100, 100)
glutCreateWindow("A basic OpenGL Window")
init()
glutDisplayFunc(display)
glutIdleFunc(display)
glutReshapeFunc(reshape)
glutPassiveMotionFunc(mouseMovement)
#check for mouse movement
glutKeyboardFunc (keyboard)
glutMainLoop()
Bethor
quelle
4
Du hast gerade ihre Hausaufgaben gemacht! Werden sie lernen, was schief gelaufen ist und wie man es behebt, oder werden sie einfach kopieren und einfügen und weitermachen?
Will
1
Zu hilfreich zu sein ist also ein Grund, abzustimmen? Und zu reparieren, was im Grunde genommen ein einziger Fehler war, ist "ihre Hausaufgaben machen"? Wenn Sie sich den vollständigen Code ansehen, den das OP auf den Pastebin gesetzt hat, werden Sie feststellen, dass ich den Code nur verschoben habe, damit ich ihn leichter lesen und diese beiden falschen Indizes ändern kann ...
Bethor
1
Dies ist tatsächlich nützlich - mein Problem war nicht
Wayne Werner
Diese Antwort ist tatsächlich nützlich und hat auch sehr wenig mit meinen eigentlichen Hausaufgaben zu tun. Wie ich ursprünglich gepostet habe, bin ich daran interessiert herauszufinden, wie die Kamera funktioniert - was bedeutet, dass ich mit diesem Code herumspielen werde. Bethor beantwortete meine Frage (es war ein einmaliger Fehler, der in das ursprüngliche Codebeispiel integriert war) und ging darüber hinaus und bereinigte den Code. Daher akzeptiert zu werden. (drat SO, um meinen Kommentar automatisch zu veröffentlichen und meine Zeit zu verkürzen, bevor ich einen anständigen Kommentar verfassen konnte)
Wayne Werner
Viel viel Code :)
daemonfire300
1

OpenGL kann Matrizen mit glPushMatrixund auf einem Stapel speichern und wiederherstellen glPopMatrix. Es ist sehr wichtig, dass jeder Push einen entsprechenden Pop hat. Wenn Sie mehr Push als Pop ausführen, wird Ihnen mitgeteilt, wenn die gesamte Zeichnung beendet ist, dass Sie den Stapel überlaufen. Wenn Sie mehr knallen als drücken, wird Ihnen sofort mitgeteilt, dass der Stapel unterfüllt ist. Auf diese Weise können Sie mit OpenGL Programmierfehler lokalisieren.

Stellen Sie also sicher, dass alle Pushs überall einen entsprechenden Pop haben.

Stellen Sie überall dort, wo Sie drücken, sicher, dass am Ausgang dieses Codeblocks ein entsprechender Pop vorhanden ist.

Wenn Ihr Code eine Ausnahme auslöst (dh wenn Sie in Ihrem Array außerhalb der Grenzen iterieren?), Müssen Sie den Pop möglicherweise in einen finally-Block einfügen, z.

def cube():
    for x in xrange(10):
        try:
            glPushMatrix()
            # draw something
        finally:
            glPopMatrix()
            # I'm trusting some code further out will catch and display your actual error now
Wille
quelle
Dies wird das Problem nicht beheben, da das Problem, wie Sie bemerkt haben, außerhalb der Grenzen iteriert, wie ich in meiner Antwort dargelegt habe, dass Sie abgelehnt haben. Dies würde ihm auch nicht helfen, seine tatsächliche Antwort zu sehen; Da die Ausnahme nicht erfasst wird, wird das Skript weiterhin beendet. Also, -1, wenn ich abstimmen könnte, besonders für die bemerkenswert schlechte Form, meine frühere Antwort zu begraben!
Bethor
Die Ausnahme vom GL-Stapel, der den unausgeglichenen Stapel erkennt, verhindert, dass er die Ausnahme der Grundursache sieht. Auf die gleiche Weise, wie er den Bericht sieht, dass er einen unausgeglichenen Stapel im Terminal hat, wird er jetzt sehen, dass er eine Ausnahme außerhalb der Grenzen hat.
Will
Meinetwegen; Ich bin mir immer noch nicht sicher, wie er einen Stapelüberlauf sieht. Der Code in seinem Pastebin löst einen IndexError an der entsprechenden Stelle für meine Installation von Python 2.7 und der neuesten PyOpenGL aus und wird korrekt ausgeführt, sobald dies behoben ist. Darüber hinaus drückt sein Code nicht mehr als er knallt, soweit ich das Lesen beurteilen kann.
Bethor
1
Dies hängt von der OpenGL-Implementierung ab. Es scheint offensichtlich, dass seine OpenGL-Implementierung aggressiv in ihrem aufgeräumten Code zählt, der durch das Abwickeln der Ausnahme ausgelöst wird.
Will
Guter Punkt ! Die Ausnahme, die alles ausgelöst hat, ist wahrscheinlich immer noch für das OP sichtbar. Ich denke, er hat gerade die letzte gesehen und nicht nach der Grundursache gesucht.
Bethor