Feste Spielgeschwindigkeit
-
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
-
-
Bloss Gewohnheit. ::Sleep heisst Sleep NUR im globalen Namespace, sonst nix.
-
Hab den Code grad net vor mir, vielleicht hab ich da Mist gebaut. Der Gedanke war: abarbeiten von normalen Window-Messages nicht verzögern. Also wenn PeekMessage ne Message geholt hat, dann nicht Sleep. Dafür Sleep im "else" Zweig, wo vorher keins war. Aber nur wenn VSync nicht an ist. Wenn VSync an ist, dann *sollte* das dafür sorgen dass an anderer Stelle irgendwas blockiert. Bei Direct3D ist das so, ob es bei OpenGL auch so ist... hm. Vermutlich nicht, das würde dann auch erklären dass du so ne hohe CPU Last hast
-
Weil die da hin gehören. Dinge die nur in einem einzigen .cpp File verwendet werden steckt man in anonymen Namespaces. "static" (internal linkage) ist pufi, und external linkage ohne anonymen Namespace ist auch pfui, wenn die Funktion nur in einem File verwendet wird.
-
FSAA hat mit der CPU Last nix zu tun, das macht nur die Arbeit der GPU schwerer, aber das schlägt sich ja nicht auf die CPU Auslastung nieder. Die kommt vermutlich von der Sleep-Änderung. Und FSAA aus hat bei mir glaub ich funktioniert. Sieht man ja sofort den Unterschied: schwammig (FSAA=an) oder scharf (FSAA=aus). Und bei mir läufts mit 100px/sec auch nicht 100% flüssig ohne FSAA.
-
Müsste ich mir ansehen. Auf jeden Fall: nicht aus dem Visual-Studio starten, denn Visual-Studio macht komische Dinge
-
Ja, liest man öfter die Empfehlung. Halte ich aber für nen Fehler. Es sollte sich mal jmd. hinsetzen und eine allgemein verwendbare Hybrid-Timer-Lib für Windows schreiben. Oder am Besten gleich für Windows/Linux/OS-X und evtl. BSD.
-
Kurz: ja, ich meine das "reset + get in Einem" was ich in timer::reset mache. Mit timeBeginPeriod() erhöht man die Auflösung von timeGetTime (hat nämlich per Default nur ca. 15ms Genauigkeit, was viel zu wenig wäre).
-
Guck mal in WindowGL::InitGL. Der Integer-Wert den man da setzt gibt an, alle wieviel Frames ein neues Bild auf dem Bildschirm angezeigt wird. Also wenn du da z.B. 10 rein schreibst, dann ruckelt alles ganz ganz böse, weil bloss alle 10 Frames (Bildaufbau vom Monitor) ein neues Bild angezeigt wird. Und bei 1 ist es eben synchronisiert, also 1 Frame am Monitor = 1 neues Bild.
Da ich aber wie gesagt von OpenGL kaum Ahnung habe weiss ich nicht wie das bei OpenGL genau funktioniert. Frag mal Google, der hilft dir -
Die "is-supported" Funktion braucht man um abzufragen ob eine OpenGL Extension vom System unterstützt wird. Die andere ist wenn ich mich recht erinnere die zum konfigurieren des Presentation-Intervals (-> VSync).
-
Siehe (2) - damit dann nicht 100% CPU Leistung verbraten wird, aus dem gleichen Grund warum du es ursprünglich drin hattest. Mit VSync sollte es nicht nötig sein, wobei ich da vermutlich noch irgendwas fehlt.
-
Vermutlich kann deine GraKa kein Pixelformat mit 32 Bit Depth-Buffer UND FSAA. Dann wird ohne FSAA gerendert, und alles ist scharf. Nur tuts dann wieder mehr zittern.
2. EDIT) Macht ja nix
p.S.: ich hab das alles relativ schnell zusammengehackt, ich bin nicht sicher ob bei der FSAA Geschichte überhaupt das von dir eingestellte Pixel-Format gesucht wird, und nicht einfach irgend eines.
-
-
hustbaer schrieb:
- Müsste ich mir ansehen. Auf jeden Fall: nicht aus dem Visual-Studio starten, denn Visual-Studio macht komische Dinge
Ok ich nehm alles zurück, Visual Studio wars
Ich habs jetzt mal intern aus dem Programm getest und es besteht vielleicht ein unterschied von 5-10 FPS wobei die ziemlich variieren und ich da nicht viel sagen kann.hustbaer schrieb:
- FSAA hat mit der CPU Last nix zu tun, das macht nur die Arbeit der GPU schwerer, aber das schlägt sich ja nicht auf die CPU Auslastung nieder. Die kommt vermutlich von der Sleep-Änderung. Und FSAA aus hat bei mir glaub ich funktioniert. Sieht man ja sofort den Unterschied: schwammig (FSAA=an) oder scharf (FSAA=aus). Und bei mir läufts mit 100px/sec auch nicht 100% flüssig ohne FSAA.
Die CPU Auslastung kam tatsächlich von irgendwo anders her, sehr wahrscheinlich wieder vom Visual Studio. Aber lagern ATI Karten nicht ein Teil ihrer arbeit auf die CPU aus, wenn die zu viel zu tun haben? Ich mein das irgendwo mal gelsen zu haben, und wie kann ich mir das sonst erklären, dass die CPU Last augenblicklich auf 100% steigt, sobald ich in einem normalen 3D Spiel mich auch nur wage AntiAliasing anzumachen?
hustbaer schrieb:
- Vermutlich kann deine GraKa kein Pixelformat mit 32 Bit Depth-Buffer UND FSAA. Dann wird ohne FSAA gerendert, und alles ist scharf. Nur tuts dann wieder mehr zittern.
Das wird es vermutlich sein. Kann man die Pixelformate der GraKa irgendwo nachgucken? Google und das Catalyst Control Center schweigen diesbezüglich. Ich habe eine Radeon X1650 series.
Und zum Schluss habe ich aber noch eine Frage grundlegend zu C++, die mir in einem halben Jahr noch nicht begegnet ist. Und zwar hast du in den return Anweisungen manchmal folgendes stehen:
return s_wglSwapIntervalEXT(interval) != 0; // oder return init.swapInterval > 0;
Ist das != 0 oder > 0 eine Art if-Abfrage? Ich habe mal nach C++ return gegooglet, aber nichts brauchbares gefunden und ein anderer Suchbegriff ist mir nicht eingefallen.
Ansonsten danke für deine Ausführliche hilfe, mir wurde jetzt einiges klarer und habe jetzt einige brauchbare Codeschnipsel
EDIT:
Sollte ich bei VSync nicht nur 60 FPS haben? Momentan liegen die zwischen 290 und 340.
- Müsste ich mir ansehen. Auf jeden Fall: nicht aus dem Visual-Studio starten, denn Visual-Studio macht komische Dinge
-
Aber lagern ATI Karten nicht ein Teil ihrer arbeit auf die CPU aus, wenn die zu viel zu tun haben?
Das wäre mir neu, allerdings bin ich auch nicht gerade Experte was aktuelle Grafikkarten angeht.
Kann man die Pixelformate der GraKa irgendwo nachgucken? Google und das Catalyst Control Center schweigen diesbezüglich.
Man kann die irgendwie mit OpenGL enumerieren. Nehe oder Google werden dir sagen wie
Und zum Schluss habe ich aber noch eine Frage grundlegend zu C++, die mir in einem halben Jahr noch nicht begegnet ist. Und zwar hast du in den return Anweisungen manchmal folgendes stehen:
return s_wglSwapIntervalEXT(interval) != 0; // oder return init.swapInterval > 0;
Lies dich mal ein was Epressions und Operatoren in C++ angeht.
a < b
ist in C++ einfach nur ne Expression, (fast) egal wo es steht. Eine Expression hat einen Wert. Expression mit Vergleichsoperatoren haben einen Wert vom Typbool
, und sindtrue
wenn die Bedingung erfüllt ist, und sonstfalse
.
Und mitif (Expression)
kann man halt Code bedingt ausführen lassen, also nur wenn der Wert der Expression, nachbool
konvertiert,true
ergibt. (Die Expression muss nicht den Typbool
haben, es geht z.B. auchif (42)
- 42 nachbool
konvertiert isttrue
(alles was nicht0
oderfalse
ist ergibttrue
), d.h. der Code im if-Block wird ausgeführt)
Man kann diesen Wert allerdings nicht nur mitif (Expression)
verwenden, sondern ihn z.B. genau so gut einer Variable zuweisen. Oder eben mitreturn
zurückgeben.Also:
return init.swapInterval > 0;
macht das selbe wie
if (init.swapInterval > 0) return true; else return false;
nur halt ohne unnötigen "Umweg".
EDIT:
Sollte ich bei VSync nicht nur 60 FPS haben? Momentan liegen die zwischen 290 und 340.Ja, sollte es. Hat es bei mir auch.
Hast du auch sicherswap_interval = 1
im settings.ini File stehen?
BTW:
use_fsaa = false
funktioniert bei mir auch wie erwartet.
-
hustbaer schrieb:
Kann man die Pixelformate der GraKa irgendwo nachgucken? Google und das Catalyst Control Center schweigen diesbezüglich.
Man kann die irgendwie mit OpenGL enumerieren. Nehe oder Google werden dir sagen wie
NeHe gibt mir nur Seiten die nicht mehr existieren und google nach "OpenGL Pixelformate" oder ähnlichem hat auch nicht viel gebacht. Aber das ist jetzt eigentlich unwichtig.
hustbaer schrieb:
Und zum Schluss habe ich aber noch eine Frage grundlegend zu C++, die mir in einem halben Jahr noch nicht begegnet ist. Und zwar hast du in den return Anweisungen manchmal folgendes stehen:
return s_wglSwapIntervalEXT(interval) != 0; // oder return init.swapInterval > 0;
Lies dich mal ein was Epressions und Operatoren in C++ angeht.
a < b
ist in C++ einfach nur ne Expression, (fast) egal wo es steht. Eine Expression hat einen Wert. Expression mit Vergleichsoperatoren haben einen Wert vom Typbool
, und sindtrue
wenn die Bedingung erfüllt ist, und sonstfalse
.
Und mitif (Expression)
kann man halt Code bedingt ausführen lassen, also nur wenn der Wert der Expression, nachbool
konvertiert,true
ergibt. (Die Expression muss nicht den Typbool
haben, es geht z.B. auchif (42)
- 42 nachbool
konvertiert isttrue
(alles was nicht0
oderfalse
ist ergibttrue
), d.h. der Code im if-Block wird ausgeführt)
Man kann diesen Wert allerdings nicht nur mitif (Expression)
verwenden, sondern ihn z.B. genau so gut einer Variable zuweisen. Oder eben mitreturn
zurückgeben.Also:
return init.swapInterval > 0;
macht das selbe wie
if (init.swapInterval > 0) return true; else return false;
nur halt ohne unnötigen "Umweg".
Ok, danke. Also war es doch das was ich geglaubt hatte
hustbaer schrieb:
EDIT:
Sollte ich bei VSync nicht nur 60 FPS haben? Momentan liegen die zwischen 290 und 340.Ja, sollte es. Hat es bei mir auch.
Hast du auch sicherswap_interval = 1
im settings.ini File stehen?
Ja hatte ich, aber ich musste die fps-Messung noch anpassen, habe einmal einen falschen Paramter benutzt
Jetzt hab ich da auch 60 FPS stehenhustbaer schrieb:
BTW:
use_fsaa = false
funktioniert bei mir auch wie erwartet.Bei mir jetzt auch. Wie gesagt lag es am Depth Buffer und and Visual Studio, dass ich gedacht habe es wär noch an.
So jetzt bin ich aber durch und habe keine Fragen mehr
Jetzt ist auch schön in einem Thread alles zusammengefasst, welche Möglichkeiten es für eine feste Spielgeschwindigkeit gibt