Feste Spielgeschwindigkeit
-
ja, wenn man sich ein wenig damit beschaeftigt, wird einem klar weshalb variable zeitschritte sehr instabil sein koennen (lernt man eigentlich auch im physik unterricht wenn man beschleunigung usw durcharbeitet).
und dass selbst feste zeitschritte oft nicht genug sind wird hier erklaert:
http://wiki.vdrift.net/Numerical_Integrationdeswegen laeuft wohl jede physic engine mit festen zeitschritten (bzw mit maximalen schritweiten und einem guten solver).
-
Pikkolini schrieb:
Das Zittern sehe ich in der Form eines "Schweifes" immernoch. Also Die Kanten werden 2 mal gezeichnet. Eine die man immer sieht, die zweite um einen Pixel verschoben, welche flackert.
Kannst du deinen Code mal irgendwo hochladen?
Vielleicht liegt es auch einfach nur an der Art wie du zeichnest.
-
@RedPuma
Du hast recht, direkt durch die Frequenz zu teilen geht auch und ist auch viel sinnvoller
Allerdngs behebt die Änderung das Problem überhaupt nicht.@hustbaer
Das Objekt zeichne ich so:glColor3ub(233,221,175); glBegin(GL_QUADS); glVertex2d(x, y); glVertex2d(x + width, y); glVertex2d(x + width, y + height); glVertex2d(x, y + height); glEnd(); glColor3ub(255,0,0); glBegin(GL_LINE_STRIP); glVertex2d(x, y); glVertex2d(x + width, y); glVertex2d(x + width, y + height); glVertex2d(x, y + height); glVertex2d(x, y); glEnd();
Oder was meinst du?
Dabei fällt mir auch direkt eine Frage ein, und zwar wieso zeichnet GL_LINE_STRIP oder GL_LINES kein Viereck, sondern lassen eine Ecke immer aus. Also das ein Pixel an der Ecke fehlt.@den Rest
Anscheindend ist es wirklich nicht sinnvoll, variable Zeitschritte zu nehmen. Also habe ich mich jett entschlossen 2 Threads zu machen.
Aber bevor ich mich da einarbeite, habe ich dazu noch eine Frage. Ist es möglich eine globale Klasseninstanz in 2 verschiedenen Threads zu "bearbeiten"?
-
Pikkolini schrieb:
@hustbaer
Das Objekt zeichne ich so:glColor3ub(233,221,175); glBegin(GL_QUADS); glVertex2d(x, y); glVertex2d(x + width, y); glVertex2d(x + width, y + height); glVertex2d(x, y + height); glEnd(); glColor3ub(255,0,0); glBegin(GL_LINE_STRIP); glVertex2d(x, y); glVertex2d(x + width, y); glVertex2d(x + width, y + height); glVertex2d(x, y + height); glVertex2d(x, y); glEnd();
Oder was meinst du?
Ich meine sind x, y, width, height Integers oder Floats, ist irgend ein Super-Sampling (Antialiasing) an oder nicht, ...?
Falls du ohne Antialiasing renderst, und die Koordinaten floats sind, probier einfach mal die Koordinaten vor dem Rendern auf Integer zu casten. Also...int xi = x; int yi = y; int x2i = xi + width; int y2i = yi + height; glColor3ub(233,221,175); glBegin(GL_QUADS); glVertex2d(xi, yi); glVertex2d(x2i, yi); glVertex2d(x2i, y2i); glVertex2d(x, y2i); glEnd(); glColor3ub(255,0,0); glBegin(GL_LINE_STRIP); glVertex2d(xi, yi); glVertex2d(x2i, yi); glVertex2d(x2i, y2i); glVertex2d(x, y2i); glVertex2d(xi, yi); glEnd();
Also habe ich mich jett entschlossen 2 Threads zu machen.
Hihi, wie du meinst.
Aber bevor ich mich da einarbeite, habe ich dazu noch eine Frage. Ist es möglich eine globale Klasseninstanz in 2 verschiedenen Threads zu "bearbeiten"?
Ja, aber nicht ohne Synchronisierung. Wobei ich "globale Klasseninstanz" schonmal lustig finde, keine Ahnung was ich mir darunter genau vorstellen soll. Ich hab es einfach mal als "ein und das selbe Objekt in zwei Threads bearbeiten" interpretiert.
-
Antialiasing ist nicht an. Wenn ich die Werte auf Integer caste, ruckelt das alles etwas.
Also wenn sich das Objekt bewegen soll steigt der x Wert nicht konstant sondern das ganze sieht so aus:
1 2 3 4 3 5 6 7 8 7 9
Das Objekt wird also immer "zurückgeworfen".Naja ich arbeite mich mal heute in Thread ein. Mal schauen was ich dann später davon habe
-
Also zurück springen dürfte er NIE, sonst machste irgendwas echt falsch. Behaupte ich mal
-
Ich habe jetzt mal ein paar Videos aufgenommen und analysiert, und springen tut er wirklich nicht, das ist nur eine optische Täuschung. Allerdings ist mir aufgefallen, dass wenn ich mit 60 fps aufnehme (mein Bildschirm hat 60 Hz), das Objekt sich zwar jede Sekunde wirklich einen Pixel bewegt, aber einige Bilder scharf und einige unscharf sind.
Woran liegt das eigentlich?
-
Daran dass du nicht auf Integers rundest, und vermutlich deine Texturen gleich gross sind wie der Platz den sie am Bildschirm einnehmen.
Entweder auf Integer runden, oder grössere Texturen verwenden.
-
Ich verwende garkeine Texturen bei dem Zeichencode steht ja auch nichts von glTexCoord2f oder so.
Und wenn ich auf Inteher runde, ruckelt es mehr als das es zittert.
-
Hihi, OK, nicht weit genug mitgedacht.
Allerdings... wenn direkt die Kanten/Linien unscharf werden, dann muss fast irgend eine Art Antialiasing aktiv sein. Mir fällt auf jeden Fall nichts ein was sonst dazu führen könnte (dürfte) dass Kanten unscharf werden.Wenn du es selbst nicht aktivierst, ... vielleicht die Default-Einstellung im Treiber?
-
Ich habe jetzt mal Antialiasing mit glDisable(GL_LINE_SMOOTH) und GL_POLYGON_SMOOTH ausgeschaltet. Etwas anderes wie ARB Multisampling etc. existiert im Code gar nicht. Aber das wäre auch nicht der Sinn der Sache, wenn ich Antialiasing auschalten müsste.
Wie gesagt arbeite ich mich jetzt in Threads ein, und lasse die logischen Berechnung getrennt vom rendern mit festen Zeitschritten ablaufen. Aber was passiert dann eigentlich wenn der Computer nicht schnell genug ist, um z.B. alle 10 ms die logischen Schritte zu berechnen?
-
Pikkolini schrieb:
Ich habe jetzt mal Antialiasing mit glDisable(GL_LINE_SMOOTH) und GL_POLYGON_SMOOTH ausgeschaltet. Etwas anderes wie ARB Multisampling etc. existiert im Code gar nicht. Aber das wäre auch nicht der Sinn der Sache, wenn ich Antialiasing auschalten müsste.
Du hast erwähnt dass einige Bilder scharf und andere unscharf sind. Antialiasing macht "unscharfe" Bilder. Natürlich musst du es deswegen nicht ausschalten
Könnte natürlich auch sein dass einfach nur der Video-Codec schuld an den unscharfen Bildern ist.
Wie gesagt arbeite ich mich jetzt in Threads ein, und lasse die logischen Berechnung getrennt vom rendern mit festen Zeitschritten ablaufen.
Mach das ruhig, wird nur vermutlich nix bringen.
Aber was passiert dann eigentlich wenn der Computer nicht schnell genug ist, um z.B. alle 10 ms die logischen Schritte zu berechnen?
Na was soll passieren, dein Spiel läuft dann zu langsam.
-
hustbaer schrieb:
Pikkolini schrieb:
Wie gesagt arbeite ich mich jetzt in Threads ein, und lasse die logischen Berechnung getrennt vom rendern mit festen Zeitschritten ablaufen.
Mach das ruhig, wird nur vermutlich nix bringen.
Ein paar Seiten vorher wurde in dies noch als beste Methode angepriesen und du willst mir jetzt sagen das bringt nichts?
Aber was passiert dann eigentlich wenn der Computer nicht schnell genug ist, um z.B. alle 10 ms die logischen Schritte zu berechnen?
Na was soll passieren, dein Spiel läuft dann zu langsam.
Hmm hast rechts das tuts ja eig immer, wenn der PC zu langsam ist.
-
Pikkolini schrieb:
hustbaer schrieb:
Pikkolini schrieb:
Wie gesagt arbeite ich mich jetzt in Threads ein, und lasse die logischen Berechnung getrennt vom rendern mit festen Zeitschritten ablaufen.
Mach das ruhig, wird nur vermutlich nix bringen.
Ein paar Seiten vorher wurde in dies noch als beste Methode angepriesen und du willst mir jetzt sagen das bringt nichts?
Nicht von mir.
Grundsätzlich ist die Methode schon gut, nur ich bin mir sicher dass du die Probleme die man damit Lösen kann einfach nicht hast.
-
Also stehe ich hier vor einem unlösbaren Problem?
Aber mittlwerweile ist es mir fast egal, da ich endlich mal weiter kommen will.
-
Pikkolini schrieb:
Also stehe ich hier vor einem unlösbaren Problem?
Aber mittlwerweile ist es mir fast egal, da ich endlich mal weiter kommen will.Ziemlich sicher nicht. Nur wie sollen wir dir sagen was du falsch machst wenn wir den Code nicht sehen?
Hab ja schon vorgeschlagen dass du den Code irgendwo uppen könntest, dann könnten wir drüber gucken. Wesentlich effizienter als zu raten und kleine Informationsstücke jedes mal umständlich nachfragen zu müssen.
-
So ich habe jetzt mal den Sourcecode und die .exe hochgeladen.
Link
-
OK.
-
Du verwendest QueryPerformanceCounter(). Das funktioniert meistens recht gut, aber nicht auf allen Systemen, daher würde ich empfehlen besser timeGetTime() zu verwenden.
-
Deine Zeitmessung ist ... nicht optimal. Das "Stoppen und wieder Starten" des Timers kann man "atomar" machen.
-
Du hast VSync nicht an.
-
Du bewegst dein Objekt mit ner Geschwindigkeit die nahe an 1 Pixel/Frame liegt, aber nicht genau 1 Pixel/Frame ist.
1 & 2 sind vermutlich egal, aber ich hab's trotzdem mal umgebaut. Vermutlich geht's auch ohne.
3 ist einfach zu machen und bringt schonmal was.
Und 4 ... da wird's interessant.
Nachdem nun VSync an ist erfolgt die Ausgabe mit ziemlich genau 60 fps (auf nem TFT).
Nun könnte man annehmen dass 60 Pixel/Sekunde extrem smooth sein müssten. Ist aber nicht so, zumindest nicht wenn man mit einer vom Bildaufbau unabhängigen Clock arbeitet. Die Umstellung auf timeGetTime() hat das Ganze vermutlich sogar noch etwas verschlimmert, allerdings war es mir zu doof das wieder zurück zu bauen.Also als kruze Erklärung, warum das überhaupt zu einer "zittrigen" Bewegung führt: wenn du mit 100 Pixel/Sekunde bewegst, dann sind das pro Frame bei 60Hz 1.66666 Pixel.
Das macht dann 0 - 1.66 - 3.33 - 5 - 6.66 - 8.33 - 10 ...
Da kein Antialiasing an ist, wird der Wert auf Integer gerundet (*).
Also 0 - 1 - 3 - 5 - 6 - 8 - 10 ...
Differenz zum jeweils vorigen Frame ist dann 1 - 2 - 2 - 1 - 2 - 2 ...
Und das sieht nunmal zittrig aus.Mögliche Lösungen:
* Höhere Geschwindigkeit führt dazu dass die Unterschiede in der pro Frame zurückgelegten Distanz (relativ) kleiner werden. Max. ist es 1 Pixel, d.h. wenn sich das Ding sowieso schon mit 10 Pixel/Frame bewegt ist der max. Fehler nur mehr 10% statt 66%. Ist natürlich kein ernst gemeinter Vorschlag, denn die Geschwindigkeit wird von anderen Faktoren vorgegeben. Nur der Vollständigkeit halber.
* Auflösung erhöhen. OK, geht natürlich nicht mehr als der Monitor kann.
* Antialiasing (FSAA) aufdrehen. Das macht alles etwas unscharf, speziell mit der einfachen Grafik die du im Moment drinnen hast. Dafür sieht die Bewegung aber sauber aus.
* Objekte verwenden die keine oder kaum Kanten die parallel zu den Bildschirmkanten verlaufen.
* Billboards statt Geometrie verwenden + sicher stellen dass jede Billboard-Textur einen ausreichend grossen "durchsichtigen" Rand hat + mit new hübschen Textur-Interpolation (=wenigstens bilinear) rendern.
Ich hab' mal Code eingebaut um FSAA zu aktivieren, kannst dir ja ansehen wie das wirkt.
p.S.: meine Änderungen sind lediglich ein "proof of concept" und entsprechend quick and dirty.
EDIT: (*): natürlich wird auch ohne FSAA subpixel genau gerendert, bloss hilft das nix bei Objekten wo alle Kanten 100% parallel zur Projektionsfläche sind.
-
-
Danke für deine ganzen Tipps und Codeverbesserungen, aber ich habe da jetzt schon eine Menge Fragen, obwohl ich noch garnicht den ganzen Code durchgearbeitet habe (da sind ja wirklich viele Änderungen drin).
1. Wieso schreibst du ::Sleep(1) und nicht Sleep(1)? Das müsste doch beides das gleiche Sein oder irre ich mich da?
2. Wieso haste du das letzte Sleep in der Programmschleife entfernt? Dadurch wird mein Prozessor wieder mit 100% gebraten
3. Wieso haste du einige Variablen und Funktionen in einen namenslosen namespace gepackt?
4. Durch das FSAA läuft es jetzt wirklich flüssig, allerdings habe ich jett eine Prozessorlast von 80% (Pentium 4 3.06 GHz). Auch wenn ich in den settings.ini den wert using_fsaa auf false setze, bleibt es anscheinend doch an. Alles läuft flüssig und der Prozessor wird immernoch übermäßig gegrillt.
5. Wenn den Task Manager oder Fraps anhabe, stottert das Spiel nurnoch unschön, und Fraps zeigt auch nurnoch 15 FPS an. Die FPS ohne ein anderes Programm muss ich noch testen.
6. Ich habe QueryPerformanceCounter() genommen, da dies angeblich genauer sein soll. Mit deiner Methode läuft aber trotzdem alles super
7. Meinst du mit "die Zeit atmoar messen", das was du in dem Code gemacht hast? Wenn ja, wozu benutzt du die Funktionen timeBeginPeriod etc. die MSDN konnte mir bis jetzt noch nicht wirklich helfen.
8. Wie funktioniert VSync? Ich habe in dem Code nur isUsingVsync() gefunden, mehr aber nicht. Diese macht das hier:
return init.swapInterval > 0;
Was hat es mit dem > 0 am Ende auf sich. Was ist dieses Swap Interval?9. Was machen die ersten beiden Funktionen in GLExtensions.cpp?
10. Wieso lässt du die Programmschleife eine Millisekunde sleepen, wenn kein VSync an ist?
So dann werde ich mir den Code jetzt mal weiter anschauen, und hoffen, dass ich noch einges verstehen werde
-
EDIT:
11. Wenn ich den Depthbuffer von 16 auf 32 Bits stelle, habe ich alles Glasklar und scharf. Gibts dabei aber irgendwelche nachteile? Ein nennenswerten Performanceeinbruch habe ich nicht gesehen.2. EDIT:
Das sollte wirklich ein edit werden und kein neuer Beitrag