Was ist die effizienteste Methode, um mehrere (in VBO gespeicherte) Objekte im Raum zu bewegen? soll ich glTranslatef oder einen Shader verwenden?

Ich versuche, die Bewegung von Objekten (im Allgemeinen) und Linienstreifen (im Besonderen) in OpenGL am effizientesten zu gestalten, und schreibe daher eine Anwendung, in der mehrere Liniensegmente mit einer konstanten Geschwindigkeit von rechts nach links verlaufen. Zu jedem Zeitpunkt wird der am weitesten links liegende Punkt entfernt, die gesamte Linie wird nach links verschoben und ein neuer Punkt wird ganz rechts von der Linie hinzugefügt (dieser neue Datenpunkt wird im laufenden Betrieb gestreamt / empfangen / berechnet) alle 10ms oder so). Um zu veranschaulichen, was ich meine, sehen Sie dieses Bild:

Da ich mit vielen Objekten arbeiten möchte, habe ich mich für die Verwendung von Vertex-Buffer-Objekten entschieden, um die Anzahl der Objekte zu minimierengl* Anrufe. Mein aktueller Code sieht ungefähr so ​​aus:

A) Richten Sie die ersten Eckpunkte ein:

# calculate my_func(x) in range [0, n]
# (could also be random data)
data = my_func(0, n)

# create & bind buffer
vbo_id = GLuint()
glGenBuffers(1, vbo_id);
glBindBuffer(GL_ARRAY_BUFFER, vbo_id)

# allocate memory & transfer data to GPU
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW)

B) Scheitelpunkte aktualisieren:

draw():

  # get new data and update offset
  data = my_func(n+dx, n+2*dx)

  # update offset 'n' which is the current absolute value of x.
  n = n + 2*dx

  # upload data 
  glBindBuffer(GL_ARRAY_BUFFER, vbo_id)
  glBufferSubData(GL_ARRAY_BUFFER, n, sizeof(data), data)

  # translate scene so it looks like line strip has moved to the left.
  glTranslatef(-local_shift, 0.0, 0.0)

  # draw all points from offset
  glVertexPointer(2, GL_FLOAT, 0, n)
  glDrawArrays(GL_LINE_STRIP, 0, points_per_vbo)

wohermy_func würde so etwas machen:

my_func(start_x, end_x):

  # generate the correct x locations.
  x_values = range(start_x, end_x, STEP_SIZE)

  # generate the y values. We could be getting these values from a sensor.
  y_values = []
  for j in x_values:
      y_values.append(random())

  data = []
  for i, j in zip(x_values, y_values):
     data.extend([i, j])

  return data

Dies funktioniert einwandfrei. Wenn ich jedoch 20 dieser Linienstreifen auf dem gesamten Bildschirm anführe, verlangsamt sich die Geschwindigkeit erheblich.Deshalb meine Fragen:

1) Soll ich glMapBuffer verwenden, um den Puffer an die GPU zu binden und die Daten direkt zu füllen (anstatt glBufferSubData zu verwenden)? Oder macht dies keinen Unterschied in Bezug auf die Leistung?

2) Soll ich einen Shader zum Verschieben von Objekten (hier Linienstreifen) verwenden, anstatt glTranslatef aufzurufen? Wenn ja, wie würde ein solcher Shader aussehen? (Ich vermute, dass ein Shader der falsche Weg ist, da mein Linienstreifen KEINE Punktfunktion ist, sondern zufällige Daten enthält).

3) Was passiert, wenn die Fenstergröße geändert wird? Wie behalte ich das Seitenverhältnis und skaliere die Eckpunkte entsprechend? glViewport () hilft nur beim Skalieren in y-Richtung, nicht in x-Richtung. Wenn das Fenster in x - Richtung neu skaliert wird, müsste ich in meiner aktuellen Implementierung die Position des gesamten Linienstreifens neu berechnen (aufrufend)my_func um die neuen x Koordinaten zu erhalten) und auf die GPU hochzuladen. Ich denke, das könnte eleganter gemacht werden? Wie würde ich das machen?

4) Mir ist aufgefallen, dass ich benutzeglTranslatef Bei einem nicht ganzzahligen Wert flackert der Bildschirm, wenn der Linienstreifen aus Tausenden von Punkten besteht. Dies liegt höchstwahrscheinlich daran, dass die für die Berechnung des Linienstreifens verwendete Feinauflösung nicht mit der Pixelauflösung des Bildschirms übereinstimmt und daher manchmal einige Punkte vor und manchmal hinter anderen Punkten angezeigt werden (dies ist besonders ärgerlich, wenn Sie keine rendern Sinuswelle, aber einige 'zufällige' Daten). Wie kann ich dies verhindern (abgesehen von der offensichtlichen Lösung der Übersetzung durch ein ganzzahliges Vielfaches von 1 Pixel)? Wenn ein Fenster von ursprünglich 800 x 800 Pixel auf 100 x 100 Pixel verkleinert wird und ich trotzdem einen Linienstreifen von 20 Sekunden visualisieren möchte, muss das Verschieben in x-Richtung irgendwie flackerfrei und mit Subpixel-Genauigkeit funktionieren, oder?

5) Wie Sie sehen, rufe ich immer anglTranslatef(-local_shift, 0.0, 0.0) - ohne jemals das Gegenteil zu tun. Deshalb verschiebe ich die gesamte Ansicht nach rechts. Und deshalb muss ich die absolute x-Position verfolgen (um neue Daten an der richtigen Stelle zu platzieren). Dieses Problem führt schließlich zu einem Artefakt, bei dem sich die Linie mit den Fensterrändern überlappt. Ich denke, es muss einen besseren Weg dafür geben, oder? Möchten Sie die x-Werte festhalten und nur die y-Werte verschieben und aktualisieren?

BEARBEITEN Ich habe das Sinuswellenbeispiel entfernt und durch ein besseres Beispiel ersetzt. Bei meiner Frage geht es im Allgemeinen darum, wie Sie Linienstreifen am effizientesten im Raum verschieben (während Sie ihnen neue Werte hinzufügen). Daher helfen hier Vorschläge wie "Vorberechnen der Werte für t -> unendlich" nicht (ich könnte auch nur die aktuelle Temperatur vor meinem Haus messen).

EDIT2 Betrachten Sie dieses Spielzeugbeispiel, bei dem nach jedem Zeitschritt der erste Punkt entfernt und am Ende ein neuer hinzugefügt wird:

t = 0

   * 
  * *    *
 *   **** *

 1234567890

t = 1

  * 
 * *    * *
    **** *

 2345678901

t = 2

 *        * 
  *    * *
   **** *

 3456789012

Ich glaube nicht, dass ich hier einen Shader verwenden kann, oder?

EDIT 3: Beispiel mit zwei Strichstreifen.

EDIT 4: basierend auf Tims Antwort verwende ich jetzt den folgenden Code, der gut funktioniert,aber bricht die leitung in zwei teile (da ich zwei anrufe vonglDrawArrays)Siehe auch die folgenden beiden Screenshots.

# calculate the difference 
diff_first = x[1] - x[0]


''' first part of the line '''

# push the matrix
glPushMatrix()

move_to = -(diff_first * c)
print 'going to %d ' % (move_to)
glTranslatef(move_to, 0, 0)

# format of glVertexPointer: nbr points per vertex, data type, stride, byte offset
# calculate the offset into the Vertex
offset_bytes = c * BYTES_PER_POINT
stride = 0
glVertexPointer(2, GL_FLOAT, stride, offset_bytes)  

# format of glDrawArrays:  mode, Specifies the starting index in the enabled arrays, nbr of points
nbr_points_to_render = (nbr_points - c)
starting_point_in_above_selected_Vertex = 0
glDrawArrays(GL_POINTS, starting_point_in_above_selected_Vertex, nbr_points_to_render)  

# pop the matrix
glPopMatrix()


''' second part of the line '''

# push the matrix
glPushMatrix()

move_to = (nbr_points - c) * diff_first
print 'moving to %d ' %(move_to)
glTranslatef(move_to, 0, 0)


# select the vertex
offset_bytes = 0
stride = 0
glVertexPointer(2, GL_FLOAT, stride, offset_bytes)

# draw the line
nbr_points_to_render = c
starting_point_in_above_selected_Vertex = 0
glDrawArrays(GL_POINTS, starting_point_in_above_selected_Vertex, nbr_points_to_render)  


# pop the matrix
glPopMatrix()

# update counter
c += 1
if c == nbr_points:
    c = 0

EDIT5 Die resultierende Lösung muss offensichtlich eine Zeile über den Bildschirm rendern - und keine zwei Zeilen, denen eine Verbindung fehlt. Die Circular Buffer-Lösung von Tim bietet eine Lösung zum Verschieben des Plots, aber ich habe am Ende zwei Zeilen anstatt einer.

Antworten auf die Frage(3)

Ihre Antwort auf die Frage