2013-02-24 12 views
9

Ich beginne mit der Verwendung von OpenGL 4 in Python (über Pyglet und einige Framework-Code kam ich aus dem Netz/schrieb mich zum Laden Shadern/Programme), aber ich Ich denke, ich verstehe die Dinge ziemlich gut, daher glaube ich nicht, dass irgendwo in meinem Code ein Problem liegt.Probleme mit OpenGL 4 VBOs und Numpy Arrays, Pyglet/Python

Also, was ist mein Problem? Es scheint, dass, wenn entweder numpy Arrays oder die Puffer eine bestimmte Größe erreichen, seltsame Dinge passieren, wenn ich zeichne. Bitte schau dir das verlinkte Bild an, um zu sehen, was ich meine. http://i.imgur.com/8Oym6VA.png?1

Auf dem Bild können Sie sehen, dass ich einige "Roboter" zeichne, von denen jeder aus 8 Boxen besteht. Die Daten für den Roboter wurden nur einmal berechnet, wobei grundlegende Würfel-Vertex-/Farb-/Indexdaten verwendet und dann geeignet übersetzt/skaliert/gedreht und an ein größeres Array angehängt wurden. Im Bild links zeichne ich 172 dieser Roboter in einem VAO, das rechte Bild hat 173 Roboter. Wie du sehen kannst, passiert seltsames Zeug, wenn ich über diese "magische" Nummer gehe. Es sieht so aus, als ob alle Scheitelpunkte irgendwie mit dem ersten Punkt verbunden sind, der auf dem Bildschirm gezeichnet wird (oberer rechter vorderer Teil des ersten gezeichneten "Körpers" des Roboters). Wenn ich den ersten Roboter irgendwohin bewege, sind alle Punkte immer noch mit diesem Punkt verbunden - um zu verdeutlichen, dass ich dafür gesorgt habe, dass der Punkt im Bild nicht auf (0,0,0) oder Ähnliches zentriert ist. Das linke Bild hat Vertex- und Farbdaten mit 131328 Floats, Indexdaten sind 49248 lang. Das rechte Bild enthält Vertex- und Farbdaten mit 132096 Floats, während Indexdaten 49536 Floats lang sind. Wenn ich die Daten in mehr als einen VAO unterteile, dann kann ich mühelos Roboter im 100 - fachen (mit 100 VAOs natürlich) problemlos zeichnen (sogar 1000 - fach Roboter mit 1000 VAOs haben gut funktioniert, abgesehen davon, dass sie ziemlich viel genommen haben) viel Speicher und arbeiten mit etwa 0,2 FPS).

Um herauszufinden, ob etwas mit den Pyglets-Klassen (oder meiner eigenen) nicht stimmt, habe ich das Ganze auch mit OpenGL-Aufrufen umgeschrieben und bin auf das gleiche Problem gestoßen. Also, sind VBOs einfach nicht so groß (ich bezweifle irgendwie, dass VBOs nur etwa 17k Dreiecke haben könnten)? Oder hat es etwas mit Numpy zu tun? (Ich habe schon früher mit größeren Arrays in Numpy gearbeitet und kann mich nicht erinnern, irgendwelche Probleme gehabt zu haben)? Ach übrigens, die Größe der Floats scheint keine Rolle zu spielen (dasselbe passiert, wenn alle Vertices in der [-1,1] -Skala sind, wenn die bis zu [-35000, 35000] gehen.

I ' Ich habe das Thema ziemlich ausführlich recherchiert, aber bei meiner Suche habe ich nichts Ähnliches gefunden - wenn es so ist, entschuldige ich mich. Alles, was ich finden konnte, war der MemoryError, wenn ich wirklich große numpy Arrays benutze, aber meine Arrays sind nicht annähernd so groß . erzeugen, dass

Mein System-Spezifikationen sind:

  • Intel Core i7
  • Nvidia GeForce GTX 465
  • Windows 8 64-Bit-
  • Python 3.3 (64-Bit)
  • Pyglet 1.2alpha1
  • Numpy Binärpaket für Python 3.3 64-Bit von here

Und während ich bin fast Ich bin mir sicher, dass mit meinem Code nichts falsch ist, ich knipse immer noch die Snippets, die mit der Zeichnung in Verbindung stehen (ich habe es auch mit Base-OpenGL-Anrufen versucht und es hat nicht besser funktioniert).

Zunächst einmal habe ich eine "Handler" -Klasse, die viele statische Daten speichern soll, so dass ich sie mit einem glDraw * -Aufruf zeichnen kann (zum Beispiel das Level des Spiels oder etwas Ähnliches).Es hat Methoden zum Hinzufügen zu seinen Daten, eine Methode, um seine VBOs und VAO und eine Zeichenfunktion zu initialisieren, die einen Stapel bekommt und daraus ableitet. Es erhält auch das Programm (Vertex/Color Shader), mit dem es zeichnet.

class Handler: 
def __init__(self, program): 
    self.vertexData = numpy.array((), dtype=GLfloat) 
    self.colorData = numpy.array((), dtype=GLfloat) 
    self.indexData = numpy.array((), dtype=GLshort) 

    self.program = program 

def initBuffers(self): 
    self.vao = GLuint() 
    glGenVertexArrays(1, self.vao) 
    glBindVertexArray(self.vao) 

    #======================================================================= 
    # Vertices 
    #======================================================================= 
    self.vertexBufferObject = pyglet.graphics.vertexbuffer.create_buffer(self.vertexData.nbytes, GL_ARRAY_BUFFER, GL_STATIC_DRAW) 
    self.vertexBufferObject.bind() 
    self.vertexBufferObject.set_data(self.vertexData.ctypes.data) 
    glEnableVertexAttribArray(0) 
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0) 

    #======================================================================= 
    # Color 
    #======================================================================= 
    self.colorBufferObject = pyglet.graphics.vertexbuffer.create_buffer(self.colorData.nbytes, GL_ARRAY_BUFFER, GL_STATIC_DRAW) 
    self.colorBufferObject.bind() 
    self.colorBufferObject.set_data(self.colorData.ctypes.data) 
    glEnableVertexAttribArray(1) 
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0) 

    #======================================================================= 
    # Index 
    #======================================================================= 
    self.indexBufferObject = pyglet.graphics.vertexbuffer.create_buffer(self.indexData.nbytes, GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW) 
    self.indexBufferObject.bind() 
    self.indexBufferObject.set_data(self.indexData.ctypes.data) 

    glBindBuffer(GL_ARRAY_BUFFER, 0) 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) 
    glBindVertexArray(0) 

    self.len = len(self.indexData) 

def addTo(self, vertices, color = None, index = None): 
    if(color != None): 
     self.colorData = numpy.append(self.colorData, color) 
    if(index != None): 
     self.indexData = numpy.append(self.indexData, index + len(self.vertexData)//4) 
    self.vertexData = numpy.append(self.vertexData, vertices) 

def draw(self, stack): 
    glBindVertexArray(self.vao) 
    self.indexBufferObject.bind() 
    self.program.install() 

    stack.push() 
    self.program.usetM4F("modelToWorldMatrix", stack.ready(), row = GL_FALSE) 
    glDrawElements(GL_TRIANGLES, self.len, GL_UNSIGNED_SHORT, 0) 
    stack.pop() 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) 
    glBindVertexArray(0) 
    self.program.uninstall() 

Und I initialisiert der Handler mit einigen sehr einfachen Code, wo translateMatrix (x, y, z) eine Matrix und applyTrans (Base, trans) trans gilt für jeden vertice (x, y, z kehrt zu übersetzen, w) in der Basis.

self.handler = Handler(self.ObjectColor) 
    for i in range(1,n): 
     self.handler.addTo(applyTrans(self.robots.vertexData, translateMatrix(2*i*(-1)**(i//2), 1.5*i*(-1)**i, 0.5*i*(-1)**i)), self.robots.colorData, self.robots.indexData) 
self.handler.initBuffers() 

Und im on_draw Teil Pyglet Fenster rufen mit

self.handler.draw() 

UPDATE:

Ich habe herausgefunden, was das Problem ist und ich fühle mich ganz und gar dumm jetzt : P. Anscheinend habe ich vergessen, den dtype eines der numpy Arrays anzugeben, und es wurde standardmäßig auf 'int32'. Da ich mit dem GL_UNSIGNED_SHORT-Flag (aka 'uint16') gezeichnet habe, wurde es ein Problem. Ich habe jetzt sichergestellt, dass es 'uint16' so lange wie möglich bleibt (bis das Maximum der Indexdaten höher als 2^16 wird) und fügte hinzu, ob indexData 'uint16' oder 'uint32' ist und fügte hinzu entsprechendes Flag für den Befehl glDraw.

Dies scheint es behoben zu haben, wie ich jetzt einfach ein paar tausend (mit 5.000 Max) Roboter zu einem VBO hinzufügen kann und es funktioniert immer noch.

Was ich immer noch nicht verstehe, ist, warum es so aussah (alle Scheitelpunkte waren mit dem ersten verbunden) und warum es begann, als es geschah. Der maximale Wert von indexData, als es noch in Ordnung war, war 32831, der maximale Wert beim Start war 33023. Also sind beide Werte offensichtlich niedriger als 2^16, also warum hat GL_UNSIGNED_SHORT nicht funktioniert? Ich lasse die Frage für ein bisschen mehr offen für den Fall, dass jemand dies beantworten kann und wird nach ein paar Tagen schließen/wenn ich eine Antwort bekomme. Vielen Dank!

+0

_Blind Mann Schuss in der dark_: Es sieht wie folgt aus: Wenn ein Dreieck kreuzt 'z = 0 'vor der Projektion, die Punkte mit' z <0' abgebildet in Richtung '-inf' und diejenigen mit 'z> 0' in Richtung' + inf'. Ja, diese Dreiecke sollten natürlich abgeschnitten werden ... –

+0

Danke für die Idee, auch wenn es falsch war. Vertice Werte spielten keine Rolle in diesem Problem (sie könnten alle < or > dann 0 und es erschien immer noch) und auch Punkte wurden nicht auf + -inf, sie gingen alle nur auf den Startpunkt (wenn Sie gedreht, könnten Sie sehen, dass es an diesem Punkt gestoppt). Ich habe herausgefunden, was das Problem war und die Frage aktualisiert. Wenn Sie Ideen zur aktualisierten Frage haben, würde ich sie gerne hören! :) – NightmareBadger

+0

Ich will das Robut für meinen Skype-Avatar ... :) – mlvljr

Antwort

1

Sie können Numpy-Float-Arrays direkt mit Vertex-Pufferobjekten verwenden. Ich habe sie jedoch nicht im Zusammenhang mit Pyglet verwendet. Etwas wie:

from OpenGL.arrays import vbo 

# setup 
vertices_gl = vbo.VBO(vertPoints) 
colours_gl = vbo.VBO(vertPoints) 

# in drawing code 
vertices.bind() 
colours.bind() 
glVertexPointer(2, gl.GL_FLOAT, 0, vertices_gl) 
glColorPointer(2, gl.GL_FLOAT, 0, vertices_gl)