Bewegendes 3D Objekt mit Spurverfolgung
-
Hallo,
ich möchte eine recht einfache Aufgabe optimieren.
Idee:
Ein Flugzeug soll in Echtzeit einen vom GPS aufgezeichneten Weg abfliegen und der zurückgelegte Weg als Linien dargestellt werden, um die erfolgten Manöver im 3D-Raum von allen Seiten zu beurteilen.Umsetzung:
Die Animiation mit DoubleBuffer und DepthTest besteht also aus dem Löschen der Grafik, dem Zeichnen der Liniensegmente bis zur aktuellen Position und des Flugzeugs an dieser letzten Position, um alles dann mit SwapBuffer darzustellen.
Bei längeren Flügen können zigtausend Liniensegmente entstehen, die bei jeder Aktualisierung durchlaufen werden müssen, bevor das Flugzeug gezeichnet werden kann.
Anstatt immer alle Segmente zu zeichnen, würde ich gerne nur das letzte Segment "nachliefern" und das Flugzeug dorthin verschieben.Versuchte Lösung:
Zeichnen des aktuellen Segmentes von A nach B im Backbuffer, Swappen und im Frontbuffer das Flugzeug an der aktuellen Position drüberzeichnen.
Beim Swappen mit dem nächsten Linien-Segment wird der Frontbuffer mit dem Backbuffer überschrieben, so dass ich das Flugzeug wieder im Frontbuffer an der aktuellen Position zeichnen kann.
Dies funktioniert zwar, aber das Flugzeug flackert wie erwartet.Wie kann man dies effizienter lösen?
Layer Planes werden in OpenGL ja nicht unterstützt und sind nur bei wenigen Grafik Devices verfügbar.Vielen Dank im Voraus!
-
naja, linien zu zeichnen sollte nicht allzu stark ins Gewicht fallen, und je nach Blickwinkel werden gar nicht alle Linien sichtbar sein. Falls doch (und falls es viele sind), dann muss die Entfernung, aus der man sich die Szene anschaut, groß sein und man kann mit einem LOD-Algorithmus arbeiten (nicht mehr alle Linien zeichen, sondern z.B. immer jeden 5. Punkt durch eine Linie verbinden, um die anderen zu approximieren).
Mit rendering-spezifischen Methoden würde ich nicht an dieses Problem herangehen. Falls du z.B. mal das Programm so erweitern willst, dass du die Kamera während der "Nachverfolgung mit Linien" manipulieren kannst (zoom, pan, rotation), dann wird sich ein solcher Ansatz schnell als unflexibel herausstellen.
-
Hallo Heinzelotto,
LOD würde im Zoom Sinn machen, um die Bahn ausserhalb der Ansicht wegzulassen.
Ansonsten möchte ich schon die Linien in der Gesamtansicht komplett ohne Approximation sehen.
Bei 1000 Segmenten ist alles kein Problem, aber die Animation wird später zunehmend langsamer.
Je nach Aufzeichnungsintervall und Flugdauer kommen schon mal über 200000 Segmente zusammen.
Ohne das bewegende Objekt lässt sich die Flugbahn ja problemlos segmentweise erweitern (siehe oben).
Das Problem ist hier das Löschen des Fliegers an der alten Stelle.lg, Mod
-
das ist eine absolut statische ansicht und nur das flugzeug bewegt sich?
kannst du einen screenshot zeigen damit man sieht wie aufwendig das gerenderte ist?
-
Hi Rapso,
Screenshot ist ohne Webspace etwas schwierig.
Stell Dir einfach ein lockeres Wollknäuel vor, dessen Faden in 100000 einzelnen Linien aufgeteilt ist und sich in einer verketten Liste verwaltet.
An dessen Ende bewegt sich (momentan noch) eine einfache Kugel.Bei kurzen Flügen kann ich immer die ganze Linie von Anfang bis zur aktuellen Position und den Flieger zeichnen und dann alles gesamt swappen.
Irgendwann wird der Flieger aber immer langsamer, weil die Anzahl der Linien stetig steigt.Der momentane Ablauf ist daher gekürzt wie folgt:
while( p2 != 0 ) { // aktuelles Segment der Flugbahn glBegin( GL_LINES ); glVertex3dv( &(p1->fX) ); glVertex3dv( &(p2.fX) ); glEnd(); SwapBuffers( wglGetCurrentDC() ); // Flugzeug an der aktuellen Position glDrawBuffer( GL_FRONT ); glCallList(4711); glDrawBuffer( GL_BACK ); p1 = p2; p2 = p2->next; }
Durch den kurzzeitigen Wechsel in den Frontbuffer wird die Linie nicht übermalt, aber es flackert halt.
LG, Mod
-
-
genau, oder imageshake.
und dein problem ist nicht das zeichnen, dein problem ist dass du jeden vertex einzeln uebergibst.
gldrawarray und "kolegen" wuerden die paar linien fluessig darstellen, deine graphikkarte langweilt sich vermutlich.
-
Danke für den Imagelink!
Das Rendern ist eigentlich total trivial und soll ungefähr so aussehen:
http://image-upload.de/image/hMDJPl/8ed76cd3ca.jpgglDrawArrays oder glDrawElements ist wegen der verketteten Liste keine Option gewesen.
Meine bislang größte Liste hatte 25MB und fast 800000 Einträge.
Die Liste erlaubt später noch Cut/Copy/Paste Funktionen.
Das Löschen und Einfügen ist damit deutlich einfacher als mit statischen Arrays.
Ausserdem beinhaltet die Liste auch Einträge, die nicht als Linie, sondern als Symbole dargestellt werden sollen (z.B. Funk-Frequenzwechsel etc.).
Somit kann ich nur sequentiell durchgehen und den Typ des Eintrags auswerten.Wirklich schade, dass OpenGL keine Layer untertützt
-
modestia schrieb:
Danke für den Imagelink!
Das Rendern ist eigentlich total trivial und soll ungefähr so aussehen:
http://image-upload.de/image/hMDJPl/8ed76cd3ca.jpgdas schaut echt nicht aus als ob es all die linien wert waere, du hast ja zig mal mehr linien als pixel.
glDrawArrays oder glDrawElements ist wegen der verketteten Liste keine Option gewesen.
1.deine verkettete liste ist vermutlich extrem unperformant fuers zeichnen.
Meine bislang größte Liste hatte 25MB und fast 800000 Einträge.
800k punkte sind 3.2MB in nem array.
Die Liste erlaubt später noch Cut/Copy/Paste Funktionen.
Das Löschen und Einfügen ist damit deutlich einfacher als mit statischen Arrays.ab und zu ein loschen und einfuegen steht vermutlich in keinem verhaeltnis zu dem andauernden durchgehen der liste, statt einem array.
zudem ist es auch ein wenig unsinning weil sie ab und zu mal was andert, es jedesmal einzeln mit glVertex zu zeichnen.
Ausserdem beinhaltet die Liste auch Einträge, die nicht als Linie, sondern als Symbole dargestellt werden sollen (z.B. Funk-Frequenzwechsel etc.).
Somit kann ich nur sequentiell durchgehen und den Typ des Eintrags auswerten.du kannst _zumindestens_ alle punkte zwischen solchen frequenzwechseln in ein array stecken und es dann am stueck mit glDrawArrays oder dergleichen abschicken. denn wenn du das nicht machst, dann macht es der treiber, jedoch hast du extremen overhead bei jedem einzelnen glvertex aufruf, weit mehr als es kostet das einmal in ein array zu stecken.
Wirklich schade, dass OpenGL keine Layer untertützt
dein problem ist vermutlich nicht die geschwindigkeit der karte, sondern dein suboptimales fuettern der daten. die loesung ist also nicht ein feature in opengl, sondern deinen code erstmal ordentlicher auf performance zu trimmen.
dein bildchen kann man vermutlich in software schneller zeichnen als du es mit einer graphikkarte machst.
dein layer heisst also gldrawarrays. alles was in einem layer sein kann, kannst du auch da hinein fuettern.
falls du faul bist, kannst du auch list dafuer benutzen.
-
Wenn die vielen einzelnen glVertex* Aufrufe der Flaschenhals sind, werde ich mal umdenken und mir aus der Liste ein (Interleaved) Array erzeugen und notfalls noch VBOs nutzen.
Erstmal vielen Dank für Deine realistische Beurteilung!
-
ich wuerde dir empfehlen, falls du die daten nur zum zeichnen benutzt, shorts statt float zu nutzen als screen positionen.
dann kurz vorm aufruf von glVertex if(x0!=x1 || y0!=y1) zu testen und ansonsten die linie zu ueberspringen, falls dieser mehr aufwand geschwindigkeit bringt, dann kannst du dir 100% sicher sein dass die einzelnen aufrufe zu glVertex das problem ist.achtung, mit float wird das nicht so gut funktionieren