OpenGL - Estouro de pilha se eu fizer, Estouro de pilha se não!

7

Estou em uma aula de multimídia na faculdade e estamos "aprendendo" o OpenGL como parte da aula. Estou tentando descobrir como a câmera OpenGL vs. modelview funciona e, por isso, encontrei este exemplo. Estou tentando portar o exemplo para Python usando as ligações do OpenGL - ele inicia o OpenGL muito mais rápido, portanto, para fins de teste é muito melhor -, mas continuo com um erro de estouro de pilha com o glPushMatrix neste código:

  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();

De acordo com essa referência , isso acontece quando a pilha da matriz está cheia.

Então pensei: "bem, se estiver cheio, deixe-me tirar a matriz do topo da pilha e haverá espaço". Eu modifiquei o código para:

  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();

E agora recebo um erro de buffer underflow - o que aparentemente acontece quando a pilha tem apenas uma matriz.

Então, eu estou apenas fora da base no meu entendimento? Ou existe alguma maneira de aumentar o tamanho da pilha da matriz?

Além disso, se alguém tiver algumas boas referências (online) (exemplos, etc.) para entender como as matrizes de câmera / modelo funcionam juntas, eu agradeceria sinceramente!

Obrigado!

EDITAR:

Aqui está a pasta do código completo: http://pastebin.com/QXxNisuA

Wayne Werner
fonte
2
Esse é o seu código inteiro? Tem certeza de que não está fazendo mais glPushMatrix que não possui o glPopMatrix correspondente? Você tem certeza de que o comando não está afetando apenas a instrução glPushMatrix?
R2d2rigo
Sim, precisamos ver seu outro código. Onde você está configurando a matriz de projeção? Você já mudou para o modo GL_MODELVIEW? (A pilha de matriz de projecção é extremamente pequeno.)
TheBuzzSaw
Definitivamente, evite seu segundo exemplo de código. Ter um glPopMatrix flutuando ali sem um glPushMatrix correspondente certamente levaria a um fluxo insuficiente. Seu primeiro exemplo de código parece bom; deve haver um problema no restante do seu código.
TheBuzzSaw 27/02
Eu apaguei minha resposta porque continha erro. Eu assumi algo que não era verdade.
Notabene
11
Por que você não pergunta isso no Stack'Flow ?
Mateen Ulhaq

Respostas:

9

Editado para adicionar: isso não é importante por enquanto, pois ainda funcionará bem e facilita o aprendizado do OpenGL, mas observe que todo o sistema de pilha de matrizes está obsoleto no OpenGL 3.xe além. Uma possível substituição é o GLM .

O código no seu pastebin nem sequer funciona para mim.

Em particular, seus índices de lista na função de exibição estão fora do intervalo (sua lista possui 10 elementos: as listas python começam em 0; você indexa de 0 + 1 a 10 + 1).

Eu acho que você também tinha alguns globais ausentes na função de manipulação do mouse, mas isso poderia ser de mim movendo o código na tentativa de pelo menos fazê-lo parecer com python;)

De qualquer forma, com essas correções, o código mostrado abaixo FUNCIONA PARA MIM, sem sinais de pilha de matriz GL sob / excedente!

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
fonte
4
Você acabou de fazer a lição de casa! Eles aprenderão o que deu errado e como corrigi-lo ou apenas copiarão e colarão e seguirão em frente?
Será
11
Então, ser muito útil é uma razão para votar? E consertar o que era basicamente um erro único é "fazer a lição de casa"? Se você olhar para o código completo da put OP no Pastebin, você vai notar que acabou de se mudar o código em torno de modo que eu pudesse lê-lo mais facilmente, e mudou esses dois índices erradas ...
Bethor
11
Isto é realmente útil - o meu problema não era
Wayne Werner
Essa resposta é realmente útil e também tem muito pouco a ver com minha lição de casa real. Como publiquei inicialmente, estou interessado em descobrir como a câmera funciona - o que significa que estarei brincando com esse código. Bethor respondeu à minha pergunta (foi um erro único, embutido no exemplo de código original), foi além e limpou o código. Daí ser aceito. (drat SO para auto-publicação meu comentário e cortar o meu tempo fora antes que eu pudesse elaborar um comentário decente)
Wayne Werner
Lotes de lotes de código :)
daemonfire300
1

O OpenGL pode armazenar e restaurar matrizes em uma pilha usando glPushMatrixe glPopMatrix. É muito importante que cada push tenha um pop correspondente - se você pressionar mais do que pop, será informado quando todo o desenho terminar que você está transbordando a pilha. Se você estourar mais do que empurra, será informado imediatamente que está sobrecarregando a pilha. É assim que o OpenGL permite localizar erros de programação.

Portanto, verifique se todos os toques em todos os lugares têm um pop correspondente.

Em todos os lugares que você pressiona, verifique se há um pop correspondente na saída desse bloco de código.

Se seu código está lançando uma exceção (ou seja, sua iteração fora dos limites em sua matriz?), Pode ser que você precise colocar o pop em um bloco finalmente, por exemplo:

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
Vai
fonte
Isso não resolverá o problema, pois, como você observou, o problema está saindo dos limites, como eu descrevi na minha resposta que você votou contra. Além disso, isso não o ajudaria a ver sua resposta real; como a exceção não foi capturada, o script ainda será encerrado. Então, -1, se eu pudesse votar, especialmente pela forma extremamente ruim de tentar enterrar minha resposta anterior!
Bethor 28/02
A exceção da pilha GL que detecta a pilha desequilibrada é o que o impede de ver a exceção da causa raiz. Da mesma forma que ele vê o relatório de que possui uma pilha desequilibrada no terminal, agora verá que tem uma exceção fora dos limites.
Será
Justo; Ainda não tenho certeza de como ele está vendo um estouro de pilha. O código em seu pastebin gera um IndexError no local apropriado para minha instalação do Python 2.7 e o PyOpenGL mais recente e é executado corretamente depois que isso é corrigido. Além disso, o código dele não empurra mais do que aparece, até onde posso ler ao lê-lo.
Bethor 28/02
11
Depende da implementação do OpenGL; parece óbvio que sua implementação do OpenGL está contando agressivamente seu código de organização que está sendo acionado pela exceção.
Será
Bom ponto! A exceção que desencadeou todo o pensamento provavelmente ainda está visível para o OP, acho que ele acabou de ver o último e não procurou a causa raiz.
Bethor 28/02