Registriert: Mo Aug 23, 2010 19:45 Beiträge: 16
Programmiersprache: Delphi und noch mehr
Hallo Leute,
ich bins mal wieder. Da ich ja ausgiebiger Fan von LED Matrizen und LED Cubes bin, kam mir der Gedanke mal mit OpenGL eine große Matrix/Cube (im Grunde is es nur eine Dimension mehr) darzustellen um damit ein wenig mit Animation rumzuspielen. Also im Grunde mein bisheriger Stand ist soweit, dass man ein Array hat wo der Zustand des aktuellen Pixels steht (an oder aus). Dieses Array wird dann mit OpenGL (OnIdle Methode) dargestellt.
Nun möchte ich gerne die Animationen fortlaufend haben und diese soll man natürlich auch ein- und ausschalten können. Im Grunde dachte ich, ich nehme dafür ein Timer den kann ich ein- und ausschalten und im Timerevent wird dann nur noch in einer Case-Anweisung überprüft welche Animation hat man ausgewählt und diese Prozedur wird dann aufgerufen.
Jetzt kommt aber der Punkt an dem ich hängen bleiben. Ich möchte erstmal eine einfach Animation in dem der ganze Cube einfach blinkt. Die Prozedur ist in dem Punkt einfach eine Periode. Im Grunde im Pseudocode sieht das so aus:
Code:
LED Cube an
500ms warten
LED Cube aus
500ms warten
So aber nun kommt das. Wie gestalte ich das 500ms warten, so dass er nebenher noch rendern kann? Sleep legt ja den aktuellen Thread schlafen und somit freezt mein Programm. Meine anderen Versuche mit Delay (GettickCount und Application.ProcessMessages) und einem anderen Thread der eine Variable hochzählt und in meiner Animationsprozedur einfach mit einer repeat ... until variable = 500 Application.ProcessMessages aufruft haben auch zu einem Freeze geführt.
So langsam weiße ich auch nicht mehr weiter und ob das mit einem 2ten Thread funktioniert habe ich auch keine Ahnung. Vielleicht weiß jemand von euch weiter und kann mir helfen ich wäre euch sehr dankbar darüber.
Dein komplettes Programm sollte in der OnIdle-Methode stattfinden. Das ist quasi deine Hauptschleife. Mit Blick auf mögliche Animationen die du vermutlich implementieren willst, solltest du zunächst solltest du die Zeit messen die seit dem letzten Frame (aka Aufruf von OnIdle) vergangen ist. Vom Prinzip kann man das mit GetTickCount machen, was allerdings extrem ungenau ist. Es ist besser QueryPerformanceCounter zu benutzen, einfach die Forensuche benutzen, dazu gibt es häufiger Fragen hier. Z.B. hier: viewtopic.php?f=10&t=10243&start=0
Nun solltest du irgendwie die Zeit in Sekunden seit dem letzten Frame in einer Variable haben, traditionell deltaTime genannt.
Nun kannst du damit eine beliebe Animation mit einem Index clock und der Länge length sehr genau abspielen. Du brauchst keiner Timer-Klasse (oder gar extra Threads o.O) mehr, du musst nur clock um deltaTime weiter rücken.
Hier mal als Beispiel eine Animation die die LED blicken lässt, aber nicht statisch an/aus sondern mit variabler Helligkeit:
Code:
// initialisierung
length := 2; // Animationsdauer 2 Sekunden
clock := 0;
direction := 1;
// update (jedes Frame)
clock := clock + direction * deltaTime;
if (clock >= length) then begin
clock := 2*length - clock; // wir werden quasi niemals genau auf length landen
direction := -1; // Richtung umkehren
end else if (clock < 0) begin
clock := -clock;
direction := 1;
end;
brightness := clock / length; // brightness liegt zwischen 0 und 1...einfach mit der Farbe multiplizieren.
Für jede LED bzw. Animation hättest du nun so eine clock-Variable. Damit es gut aussieht empfiehlt es sich noch ein smoothstep auf die Interpolation anzuwenden. Dies wirkt deutlich weicher/besser:
Registriert: Mo Aug 23, 2010 19:45 Beiträge: 16
Programmiersprache: Delphi und noch mehr
So ich mir das nun nochmal genauer angeschaut. Und soweit ich das richtig sehe, dann meinst du auch das ich die Anweisungen wie Cube an, Cube aus, Ebene 3 an, Säule 8 an auch im Render darstellen soll oder? Das ist doch dann eigentlich viel mehr Rechenarbeit oder nicht?
Ich hätte da halt schon gern die ganzen Animation in einer Unit und die "Zeichenroutinen" (also einfach schnell ne Anweisung Cube an die dann das Array füllt oder Rahmen der Größe 4) in einer anderen Unit, denn natürlich habe ich auch vor einen größeren LED Cube zu bauen, dann kann ich die Animation einfach "übersetzen".
So ich mir das nun nochmal genauer angeschaut. Und soweit ich das richtig sehe, dann meinst du auch das ich die Anweisungen wie Cube an, Cube aus, Ebene 3 an, Säule 8 an auch im Render darstellen soll oder? Das ist doch dann eigentlich viel mehr Rechenarbeit oder nicht?
Ich bin mir nicht ganz sicher was du meinst. Niemand hindert dich daran deinen Quellcode schön zu strukturieren. Üblicherweise sieht OnIdle ungefähr so aus:
Code:
deltaTime := ....Zeitmessung...
Update(deltaTime);
Render();
Die ganze Logik mit deinen Animationen findet in Update statt. Hier würdest du eben für jede LED eine Farbe setzen (oder was auch immer). Die Funktion Render rendert einfach nur ohne irgendwas am Zustand der Szene zu ändern. Diese Trennung wird insbesondere dann sinnvoll wenn du später feststellst das du für irgendeinen Spezialeffekt (Schatten, Reflektion, Glow, ...) die Szene mehrfach rendern musst.
Registriert: Mo Aug 23, 2010 19:45 Beiträge: 16
Programmiersprache: Delphi und noch mehr
Naja so wie du das meinst so sehe ich das ja dann noch ein, dann zähl ich in dieser Funktion dann die Zeit hoch und hab dann eine Statusvariable (in dem Falle dann Boolean). Im Prinzip dann so (ist jetzt nur Pseudocode):
Code:
inc(i);
if i = 500 and ison then
begin
led cube off
i = 0
ison = false
end
else if i = 500 and not ison then
begin
led cube an
i = 0
ison = true
end
Wie mache ich das denn nun, wenn ich zum Beispiel eine durchlaufende Ebene haben will? Da wäre dann die Logik in etwa so:
Code:
ebene 1 an
500 ms warten
ebene 1 aus
ebene 2 an
500 ms warten
ebene 2 aus
ebene 3 an
500 ms warten
//und so weiter
Dann hätte ich ja theoretisch mehrere Statusvariablen, richtig? Oder gäbe es da auch eine besser Möglichkeit eine Wartezeit zu realisieren?
Dieses if-Konstrukt lässt sich natürlich auch leicht als Schleife bauen. Das ist natürlich die einfache Lösung.
Du kannst dir auch ein richtiges Animationssystem bauen. Etwa eine Basisklasse Animation. Davon eine EbenenAnimation ableiten die eine Ebene an oder ausschalten kann. Dann definierst du dir noch eine AnimationSequence, so dass du mehrere Objekte der Klasse Animation hintereinander ausführen kannst.
Mitglieder in diesem Forum: 0 Mitglieder und 9 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.