Das mystische Ruckeln

Übersicht BlitzBasic Blitz3D

Gehe zu Seite 1, 2  Weiter

Neue Antwort erstellen

faeX

Betreff: Das mystische Ruckeln

BeitragSo, Jun 20, 2010 23:59
Antworten mit Zitat
Benutzer-Profile anzeigen
Ware Programmierer blühen bekanntlich erst in der Nacht richtig auf.
Leider haben wir in unserem Projekt ein seltsames Ruckeln.
Wir haben es isoliert und hier in diesem >>>Paket<<< hochgeladen. Es scheint, als würde die Figur jede Sekunde einen Satz nach vorne machen, erklären können wir uns das nicht. Sad

Wie kann man das verhindern?
Kombinationen aus Vollbild, Flip 0 / 1 etc. haben wir schon probiert.

Noobody

BeitragMo, Jun 21, 2010 0:14
Antworten mit Zitat
Benutzer-Profile anzeigen
Sobald ich den Timer rausnehme, funktioniert es bei mir wunderbar.

Ich habe nun nicht wirklich eine Erklärung für den Grund, da ja WaitTimer in deinem Beispiel ziemlich die ganze Zeit über eine konstante Zeit benötigt (ich habs nachgemessen). Das einzige, was ich mir vorstellen könnte, wäre, dass der Timer auf irgendeine Weise eine Event-Schlange blockiert und so zu einem kurzen Ruckeln führt - aber auch das klingt ziemlich unplausibel.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

M0rgenstern

BeitragMo, Jun 21, 2010 0:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Hey.
Du hast Recht.
Ohne den Timer funktioniert wunderbar.
Ich wüsste aber auch nicht woran das liegt. Hab in allen anderne Projekten mit Draw3D(2) auch mit Waittimer gearbeitet und afaik arbeiten die Beispiele auch damit.

Hab selbst auch echt keinen Plan was das sein könnte.
Vielleich fällt ja sonst jemandem noch was auf.

Thx schonmal dafür^^

Den timer rauszunehmen kann aber auch nicht die lösung sein.... (100% Prozessorlast^^)

Lg, M0rgenstern.

Chrise

BeitragMo, Jun 21, 2010 0:53
Antworten mit Zitat
Benutzer-Profile anzeigen
bei mir lag so ein ruckeln mal daran, dass eine system dll doppelt auf war xD
Ich hafte nicht für irgendwelche schäden, wenn du im task manager rumspielst ^^
Llama 1 Llama 2 Llama 3
Vielen Dank an Pummelie, der mir auf seinem Server einen Platz für LlamaNet bietet.

hectic

Sieger des IS Talentwettbewerb 2006

BeitragMo, Jun 21, 2010 1:16
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich kann euch beruhigen, hat nichts mit der Draw3D2 zu tun.

Erklärung:

Ein normaler Flachbildschirm arbeitet mit genau 60FPS. Nun hat leider der Blitz-Timer eine grässliche Macke. Er berechnet das ähnlich wie folgt: Int (1000/60) =16 mit den 16 (statt 16.6666) wird dann weiter gearbeitet. Es kommt zu den unvermeintlichen Interferenzen zwischen Bildaufbau der Grafikkarte und dem des Bildschirmes. Leider nützt es nichts einfach CreateTimer(60.0) zu machen. Was zumindest etwas Abhilfe schafft, aber das Problem auch nicht komplett beseitigt ist die FPS auf 58 zu stellen. Denn Int (1000/58) =17 was zumindest etwas näher an 16.6666 dran ist als 16 Integer. Aus diesem Grund hab ich auch in allen meinem Beispielen in der Draw3D2 mit 58FPS gearbeitet.

2D Daddel & Beweis -Code: [AUSKLAPPEN]
Graphics 800,600,0,2
SetBuffer BackBuffer()

;Bei 58 FPS tretten seltener Störungen auf, als bei 60 FPS

Local Timer=CreateTimer(58)
Local Position
Local Count


While Not KeyHit(1)
   Position=(Position+5) Mod 40
   
   For Count=0 To 800 Step 40
      Rect Count+Position,0,20,500,1
   Next
   
   WaitTimer Timer
   Flip 0
   Cls
Wend
End

Im Beispiel DrawXTD #99, (WIP) Physik Auto.bb der Draw3D2 hab ich mit Delay versucht dem ganzen aus dem Wege zu gehen. Und tatsächlich bekommt man so einen viel sauberen Bewegungsablauf hin.

Statt einem Timer, nimmt man dann folgenden Code: [AUSKLAPPEN]
   MSA=MSC:MSC=MilliSecs()
   WAT=WAT+(16.66-(MSC-MSA))/2
   If WAT>16 Then WAT=16
   If WAT<0 Then WAT=0
   Delay WAT

Das ist dann zumindest so genau, dass alle paar Sekunden mal eine Störung auftritt. Dafür ''wandert'' diese allmählich dem Bildschirm entlang. Also die Interferenz zwischen Computer und Bildschirm. Äußert sich dadurch, dass unter und oberhalb der Störung zwei verschiedene ''Zeiten'' abgebildet werden.

Komplette Rätzelslösung ist nach wie vor das gehasste Flip 1, welches den Prozessor bis zur Ohnmacht auslastet. Es sei jedoch gesagt, in einem Spiel mit Scrolling, Hintergrund, Schüssen und Gegnern fällt das auch nicht mehr so auf. Nur in solchen Reinproben - schwarzer Bildschirm, eine Figur etc... - kommt einem das Mittagessen hoch.

Edit1: Alle Jahre mal wieder die eine und selbe Frage. Wink

FireballFlame

BeitragMo, Jun 21, 2010 3:14
Antworten mit Zitat
Benutzer-Profile anzeigen
Jetzt weiß ich auch wieder, warum ich mir damals immer einen eigenen "Timer" mit Delay geschrieben hab...
PC: Intel Core i7 @ 4x2.93GHz | 6 GB RAM | Nvidia GeForce GT 440 | Desktop 2x1280x1024px | Windows 7 Professional 64bit
Laptop: Intel Core i7 @ 4x2.00GHz | 8 GB RAM | Nvidia GeForce GT 540M | Desktop 1366x768px | Windows 7 Home Premium 64bit

faeX

BeitragMo, Jun 21, 2010 7:26
Antworten mit Zitat
Benutzer-Profile anzeigen
@hectic: Danke für deinen ausführlichen Post! Irgendwie an sowas haben wir schon gedacht, aber so genau konnten wir uns das natürlich nicht erklären. Smile

hectic

Sieger des IS Talentwettbewerb 2006

BeitragMo, Jun 21, 2010 8:24
Antworten mit Zitat
Benutzer-Profile anzeigen
Was ich jedoch schon gelesen, aber noch nicht selber bestätigen konnte ist, dass einige Prozessortypen wohl auch mit Delay nicht klar kommen. Soll wohl den selben Effekt haben, wie Flip 1. Betrifft aber wohl nur ältere Prozessoren.

Ich zu meinem Teil werde so lange es nicht sonderlich auffällt mit dem Blitztimer arbeiten, und nur in Sonderfällen meinen Delaytimer einsetzen.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D
 

vanjolo

BeitragMo, Jun 21, 2010 10:57
Antworten mit Zitat
Benutzer-Profile anzeigen
Timer und Delay verursachen auf meinem APC (P4, 3GHZ) ruckeln. Da lieber Flip1. Bis heute ist der Prozessor davon nicht abgeraucht Very Happy

Übrigens scheinen Firefox und PaintShop Pro auch "Flip1" (*GRINS*) zu verwenden. Denn die beiden Programme fordern auch immer 100%
Smile
***************************
in Entwicklung:
Tank Battles - Panzeraction
Pacific Battles - Rundenstrategie
abgeschlossenes Projekt: Harrier Assault

hectic

Sieger des IS Talentwettbewerb 2006

BeitragMo, Jun 21, 2010 12:01
Antworten mit Zitat
Benutzer-Profile anzeigen
Dann hast du vermutlich einen Bildschirm der nicht mit 60FPS, sondern mit 75FPS arbeitet?

Die 100% Prozessorlast soll weniger diesen vor dem Tod bewahren, als viel mehr das System nicht unnötig ausbremsen, oder bei mobilen Rechnern die Akkulaufzeit unnötig plätten.
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D

Noobody

BeitragMo, Jun 21, 2010 12:36
Antworten mit Zitat
Benutzer-Profile anzeigen
hectic hat Folgendes geschrieben:
Nun hat leider der Blitz-Timer eine grässliche Macke.

Dieses Mal ist aber nicht Blitz schuld. Es ist einfach unmöglich, auf OS-Ebene einen Timer zu erstellen, der genauer als Millisekunden ist. Die Systemuhr ist nur auf Millisekunden genau und die Timer-Funktionen von Windows sind ebenfalls auf Ganzzahlen begrenzt. Was ich bisher von Linux gesehen habe, scheint zu bestätigen, dass das Problem nicht nur Windows-spezifisch ist.

Rein theoretisch müsste man auf Interrupt-Ebene genauere Zeitmessungen hinbekommen - zumindest ging das auf einem simpleren Prozessor, mit dem ich mal arbeitete. Ich bin aber nicht sicher, ob das noch möglich ist, wenn gleichzeitig noch ein OS darauf läuft. Schätzungsweise kommt man sich da mit dem OS in die Quere.


hectic hat Folgendes geschrieben:
Was zumindest etwas Abhilfe schafft, aber das Problem auch nicht komplett beseitigt ist die FPS auf 58 zu stellen.

Zumindest bei mir wird das Ruckeln dann um einiges schlimmer (auch 60 Hz). Nach ein wenig Herumprobieren scheint das Ruckeln einem verpassten Frame zu entsprechen. Das Ruckeln wird also weniger stark, wenn man einfach die Framerate z.B. verdoppelt, da man dann nur ein 'halbes' Frame verpasst im Vergleich zu vorher. Der Beispielcode von hectic, abgeändert BlitzBasic: [AUSKLAPPEN]
Graphics 800,600,0,2
SetBuffer BackBuffer()

;Bei 120 FPS treten weniger starke Störungen auf als bei 60 FPS

Local Timer=CreateTimer(120)
Local Position#
Local Count


Local Frame
While Not KeyHit(1)
Position=(Position+2.5) Mod 40

For Count=0 To 800 Step 40
Rect Count+Position,0,20,500,1
Next

WaitTimer Timer
Flip 0
Cls
Wend
End

Wirklich sauber ist das aber nicht, da man so die Rechnungslast ebenfalls verdoppelt.

Die einzige wirkliche Lösung ist nach wie vor das verwenden von VSync, wie es ja in den meisten Spiele heute getan wird. Bei einem Vollbild-Spiel ist ein ausgelasteter Prozessorkern ja noch durchaus zu verkraften, bei Fensterspielen könnte man zumindest noch eine entsprechende Option im Menü einbauen. Wirklich aufgefallen ist mir dieses 'Frameskipping' in Blitz-Spielen aber noch nie, also wird es, von speziellen Beispielen mal abgesehen, wohl auch kein so grosses Problem sein, wenn der ganze Bildschirm voll ist mit Grafiken - da hat der Spieler andere Dinge, auf die er sich konzentrieren muss Razz
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun
 

vanjolo

BeitragMo, Jun 21, 2010 17:19
Antworten mit Zitat
Benutzer-Profile anzeigen
hectic hat Folgendes geschrieben:
Dann hast du vermutlich einen Bildschirm der nicht mit 60FPS, sondern mit 75FPS arbeitet?


Ich habe 2 Bildschirme am APC, beide mit 60 Mhz. Ich habe jetzt mal Nobodys Code probiert und was mir da auffällt ist, dass das Ruckeln am analog angesteuerten Bildschirm sehr viel schlimmer ausfällt als am DVI.

Keihne Ahnung warum...
***************************
in Entwicklung:
Tank Battles - Panzeraction
Pacific Battles - Rundenstrategie
abgeschlossenes Projekt: Harrier Assault

Midimaster

BeitragMo, Jun 21, 2010 17:38
Antworten mit Zitat
Benutzer-Profile anzeigen
ich war ja noch nie ein Freund von WaitTimer() (was ja bekannt sein dürfte... Laughing ), da WaitTimer eben nicht mit dem Vsync synchron läuft, bloß weil jemand CreateTimer(60) schreibt.

Und hier kommt nun wieder mal das gute alte DELAY ins Spiel, mit dem sich die Synchronisierung mit dem Vsync "hinkriegen" läßt:

1.
BlitzBasic: [AUSKLAPPEN]
Flip 1 

....wartet auf VSync

2.
Danach wird die Zeit gespeichert:
BlitzBasic: [AUSKLAPPEN]
LastFlip=MilliSecs()


3.
Jetzt geht es an den Anfang der Main-Schliefe zurück und alles nötige wird abgearbeitet.

4.
Unmittelbar vor dem FLIP 1 wird dann das Programm für den Zeitrest schlafen geschickt, der noch auf 15msec (mutige machen 16msec) fehlt:
BlitzBasic: [AUSKLAPPEN]
Delay 15-MilliSecs()+LastFlip


5.
Jetzt wird der FLIP 1 nur 1msec verbraten, dann beginnt das Spiel von vorne

Pseudocode:
BlitzBasic: [AUSKLAPPEN]
Repeat
;MoveEntitys...
UpdateWorld()
RenderWorld()
;2D_Kram....

Delay 15-MilliSecs()+LastFlip
Flip 1
LastFlip=MilliSecs()

Until KeyHit(1)
BlitzBasic: [AUSKLAPPEN]

							

hectic

Sieger des IS Talentwettbewerb 2006

BeitragMo, Jun 21, 2010 17:43
Antworten mit Zitat
Benutzer-Profile anzeigen
Das ''kurz vor dem Flip 1 noch mit Delay abwarten'' bringt leider 0 Prozessorschonung. Hab ich auch schon alles probiert. Da kann man gleich Flip 1 allein nehmen.

Edit1: ok, ich nehms zurück. Funktioniert perfekt. Wink
 

vanjolo

BeitragMo, Jun 21, 2010 22:09
Antworten mit Zitat
Benutzer-Profile anzeigen
Könnt ihr da mal einen Beispielcode zaubern. Ich bin gespannt! Very Happy
***************************
in Entwicklung:
Tank Battles - Panzeraction
Pacific Battles - Rundenstrategie
abgeschlossenes Projekt: Harrier Assault
 

BIG BUG

BeitragMo, Jun 21, 2010 22:15
Antworten mit Zitat
Benutzer-Profile anzeigen
Hierfür muss aber bekannt sein, mit welcher Refreshrate der aktuelle Bildschirmmodus arbeitet und auch viele TFT arbeiten z.B. mit 75 Hz.
Ich hatte hier schon probiert einfach mit VSYNC bzw. FLIP 1 die Hz zu messen, aber selbst mit vorgeschaltetem Delay und mehreren FLIP 1 durchläufen kam es immer mal wieder zu Unschärfen(außerhalb Rundungsungenauigkeiten).
Mit Hilfe einer externen DLL / UserLib könnte man die aktuelle Wiederholrate aber möglicherweise einfach auslesen.
B3D-Exporter für Cinema4D!(V1.4)
MD2-Exporter für Cinema4D!(final)

Midimaster

BeitragMo, Jun 21, 2010 22:37
Antworten mit Zitat
Benutzer-Profile anzeigen
Man darf die optimale Wartezeit bei Delay einfach nicht bis zum letzten ausreizen, dann erhält man auch bei berechneter Bildschirmfrequenz einen vernünftigen Wert.


BlitzBasic: [AUSKLAPPEN]
Global zeit%=MilliSecs()+500
Global fps%=0
Repeat
Flip 1
fps=fps+1
Until Zeit<MilliSecs()
Print "optimales Delay:" + (Int(500/fps)-1)

WaitKey

BladeRunner

Moderator

BeitragDi, Jun 22, 2010 10:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Zitat:
Dieses Mal ist aber nicht Blitz schuld. Es ist einfach unmöglich, auf OS-Ebene einen Timer zu erstellen, der genauer als Millisekunden ist. Die Systemuhr ist nur auf Millisekunden genau und die Timer-Funktionen von Windows sind ebenfalls auf Ganzzahlen begrenzt. Was ich bisher von Linux gesehen habe, scheint zu bestätigen, dass das Problem nicht nur Windows-spezifisch ist.

Hier muss ich mal widersprechen: Zumindest unter halbwegs neuer Hardware und Windwos sollte das erstellen eines sehr feinen Timers mittels QueryPerformanceCounter kein Problem darstellen. Linux und MaxOS haben es da nach meinen Recherchen etwas schwieriger, da keine Systemfunktionnen dafür implementiert sind, aber auch da habe ich mit etwas googlen eine Lösung gefunden.
Diese Timer sind zwar nicht hochakkurat, aber zumindest um einiges genauer als die Millisekunden der Systemuhr.
(Wenn ich es richtig verstanden habe werden die Prozessorclicks als Maß genommen und anhand der vorgegebenen Frequenz umgerechnet. Hier könnte es natürlich zu Problemen kommen wenn sich eine CPU dynamisch takten kann, aber zumindest einen Blick sollte es wert sein Smile
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92

Noobody

BeitragDi, Jun 22, 2010 12:08
Antworten mit Zitat
Benutzer-Profile anzeigen
Von der Benutzung von QueryPerformanceCounter wird meist abgeraten, da sie nicht sehr zuverlässig ist. Zum einen ist es sehr schwierig, die Taktrate der CPU herauszufinden, um die CPU-Ticks in Zeit umzurechnen. QueryPerformanceFrequency, welche eigentlich dafür geschaffen wurde, beachtet nicht, dass CPUs sich auch dynamisch rauf- und runtertakten können; ausserdem scheint die Funktion auf einigen Systemen sehr buggy zu sein (hier nachzulesen).
Grösstes Problem sind allerdings heutige Multicore-Systeme. Die einzelnen Cores müssen den Tick-Counter nicht unbedingt synchronisieren, daher kann die gemessene Zeit auch wild vor und zurückspringen, je nach dem, auf welchem Kern der eigene Thread gerade ausgeführt wird.

Für Timer ist die Funktion eher weniger geeignet. Im Prinzip will man ja mit einem Timer Rechenzeit dem System zurückgeben, bis der Timer tickt (dafür gibt es ja SetTimer aus der WinAPI). Wenn man aber nur eine Zeitmessfunktion zur Verfügung hat, ist das nicht möglich, da man selber ständig prüfen muss, ob die Zeit bis zum nächsten Tick bereits verstrichen ist. Um hier die notwendige Genauigkeit (Mikrosekunden) zu erreichen, kann die Schleife nicht in der Zwischenzeit noch Rechenzeit dem System zur Verfügung stellen.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

faeX

BeitragSa, Jul 17, 2010 13:15
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich grabe diesen Thread nochmal aus, da ich die letzten 3 Wochen in Portugal war und somit hier nicht antworten konnte.

Eure Vorschläge haben mich weitergebracht, insbesondere das Delay vor der vertikalen Synchronisation.
Diese waren allerdings NICHT die endgültige Lösung. Das Problem bestand in der Frameunabhängigen Programmierung. Auf meinem ganz alten Laptop bekam ich das ganz besonders zu spüren.
Offensichtlich waren die Zeitabstände zwischen den Frames recht sprunghaft. Deswegen habe ich beschlossen nicht den tatsächlichen Zeitabstand zur Berechnung zu nehmen, sondern einen "interpolierten" Wert.

BlitzBasic: [AUSKLAPPEN]
Const fDELTABUFFERINFLUENCE# = .05
Const fAVERAGEDELTAFLOW# = .95

Global fTimeScale# = 1 ; Zeitskalierung (fuer SlowMotion etc.)
Global fDelta# ; Deltawert, mit dem gerechnet wird
Global iMS% ; Spielzeit
Global iLastUpdate% ; Letzter Zeitpunkt eines Updates
Global iLastFlip% ; Zeitpunkt des letzten Zeichenpufferaustauschs
Global fDeltaBuffer# ; Delta, das noch aufgeholt, oder vertroedelt werden muss
Global fAverageDelta# = 16.66 ; Erwartetes Delta

; Zum Spiel
Const fPLAYERFACTOR# = .995
Const fPLAYERSPEED# = .01

Global fPlayerX#, fPlayerY#
Global fPlayerXVelocity#, fPlayerYVelocity#

Const iPLAYERRADIUS% = 16

; Initiieren
Graphics 1024, 768, 32, 2
SetBuffer BackBuffer()

iLastUpdate = MilliSecs() - fAverageDelta
While Not KeyHit(1)

Local fRealDelta# ; Taetsaechlich vergangene, skalierte Zeit
Local iFlipWait% ; Letzter Flip

; "Fluessiges" Delta, keine harten Spruenge
fRealDelta = (MilliSecs() - iLastUpdate)
fDeltaBuffer = fDeltaBuffer + (fRealDelta - fAverageDelta)
fDelta = fTimeScale*fAverageDelta + fDeltaBuffer*fDELTABUFFERINFLUENCE
fDeltaBuffer = fDeltaBuffer*(1 - fDELTABUFFERINFLUENCE)
fAverageDelta = fAverageDelta*fAVERAGEDELTAFLOW + fRealDelta*(1 - fAVERAGEDELTAFLOW)

iLastUpdate = MilliSecs()

; Updates
If KeyDown(28) Then
fTimeScale = .2
Else
fTimeScale = 1
EndIf

fPlayerXVelocity = (fPlayerXVelocity + (KeyDown(205) - KeyDown(203))*fPLAYERSPEED*fDelta)*fPLAYERFACTOR^fDelta
fPlayerYVelocity = (fPlayerYVelocity - (KeyDown(200) - KeyDown(208))*fPLAYERSPEED*fDelta)*fPLAYERFACTOR^fDelta
fPlayerX = fPlayerX + fPlayerXVelocity*fDelta
fPlayerY = fPlayerY + fPlayerYVelocity*fDelta
If fPlayerX < -iPLAYERRADIUS Then fPlayerX = GraphicsWidth() + iPLAYERRADIUS
If fPlayerY < -iPLAYERRADIUS Then fPlayerY = GraphicsHeight() + iPLAYERRADIUS
If fPlayerX > GraphicsWidth() + iPLAYERRADIUS Then fPlayerX = -iPLAYERRADIUS
If fPlayerY > GraphicsHeight() + iPLAYERRADIUS Then fPlayerY = -iPLAYERRADIUS

; Zeichnen
Cls
Oval fPlayerX, fPlayerY, iPLAYERRADIUS*2, iPLAYERRADIUS*2, True
Text 0, 0, "Delta: " + fDelta
Text 0,12, "AverageDelta: " + fAverageDelta
Text 0,24, "RealDelta: " + fRealDelta
Text 0,36, "TimeScale: " + fTimeScale
Text 0,60, "Hold down enter for timeshift!"

iFlipWait = 15 - (MilliSecs() - iLastFlip)
If iFlipWait > 0 Then Delay iFlipWait
Flip True
iLastFlip = MilliSecs()

Wend

Gehe zu Seite 1, 2  Weiter

Neue Antwort erstellen


Übersicht BlitzBasic Blitz3D

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group