Tiefenunschärfe
Bitte haben Sie etwas Geduld und nehmen Sie keine Änderungen vor, bis der Artikel hochgeladen wurde. |
Inhaltsverzeichnis
Realität und Virtualität
Bevor wir zum Programmieren übergehen erstmal ein paar Kleinigkeiten vorweg. Wen diese nicht interessieren, kann den gesamten Punkt 1 eigentlich überspringen und direkt bei 2.1 anfangen. Ansonsten geht es los mit folgender Frage:
Was ist Tiefenunschärfe?
Die sogenannte Tiefenunschärfe ist ein Effekt, den zu mindest aus der Realität jeder kennt, (und ich meine damit ausnahmslos jeder, der nicht gerade blind ist,) dem aber kaum jemand große Beachtung schenkt. Das liegt hauptsächlich daran, dass es sich um einen Effekt handelt, der für das menschliche Auge (bzw. für die beiden menschlichen Augen) vollkommen alltäglich ist.
Eine theoretische Praxisübung: Daumenakrobatik.
Zur Demonstration nehme man seinen rechten Daumen (oder irgendeinen anderen Finger) und halte ihn vor einen größeren, entfernten Gegenstand wie zum Beispiel eine Wand. Dann fokussiere man mal den Daumen im Blickfeld. Was uns interessiert ist jetzt nicht, wie schön unser Daumen denn aussieht, sondern viel mehr was mit dem Hintergrund passiert. Er verschwimmt und solange wir unseren Daumen klar erkennen können, können wir den Hintergrund nur unscharf sehen. Anders herum können wir unseren Daumen nicht klar erkennen, während wir den Hintergrund fokussieren. Dieser Effekt verstärkt sich übrigens, je größer der Abstand von Daumen und Hintergrund ist. Das funktioniert übrigens auch seitlich. Man halte seine zwei Daumen auf eine Entfernung von etwa fünf Zentimetern nebeneinander, und versuche mal Beide gleichzeitig zu fokussieren.
Erkenntnis
Nach spätestens einer Minute anstrengender Verrenkungen sollte man gemerkt haben, was der hauptsächliche Aspekt ist, um den es hier geht; Der Mensch ist nicht in der Lage, mehrere Bildpunkte gleichzeitig scharf darzustellen. (Kameras haben übrigens das selbe Problem)Beispiel zur tiefenunschärfe |
Virtuelle Tiefenunschärfe
Jetzt erst einmal weg vom "RL". Tiefenunschärfe ist wie wir nun herausgefunden haben sollten kein Effekt, der unglaublich viel Spannung erzeugt wie zum Beispiel eine Explosion. Trotzdem bin ich der Meinung, dass sie in vielen Spielen fehlt und optisch gesehen einiges hermachen kann. Die fehlende Tiefenunschärfe ist oftmals der Grund, warum Computerspiele oder -Animationen sehr künstlich wirken. Warum? Ganz einfach: Ein jeder Mensch mit gesundem Geist, hält das was er gewohnt ist für realistisch, beziehungsweise reell. Er ist darauf spezialisiert, Muster zu erkennen und wieder zu erkennen. Auf unser Beispiel bezogen heißt das: wir sind es gewohnt, immer nur einen bestimmten Punkt in unserem Blickfeld scharf erkennen zu können. Da in Computerspielen häufig einfach alles gleichermaßen scharf gestellt wird, bemerkt unser Unterbewusstsein den Unterschied und stempelt das gesehene als künstlich ab. In der folgenden Anleitung versuche ich eine Technik zu erläutern, wie man Tiefenunschärfe ganz simpel in OpenGL umsetzen kann.
Programmierung
Die Technik, die ich hier erläutern möchte, ist wirklich sehr simpel und erfordert nicht all zu viel an Vorkenntnissen, ist aber auch nicht unbedingt für Anfänger geeignet, da man doch das eine oder andere falsch machen und somit die Performance in den Keller reißen kann. Eine Voraussetzung wäre eventuell glAccum, es ist aber nicht all zu schlimm, wenn man damit noch nicht gearbeitet hat.
Praktische Theorie
So. Jetzt geht's an's Programmieren. Womit fangen wir an? Richtig.
Die Grundidee
Wir wollen also jetzt einen Blureffekt, der abhängig vom Abstand zu einem bestimmten Punkt verschieden stark ist. Je weiter entfernt, umso stärker. Mit anderen Worten: Blurstärke ~ Radius. Nun wäre es reichlich sinnlos, für jeden Bildpunkt, der gezeichnet wird einen Radius zu berechnen und jeden Punkt einzeln zu blurren. Das wäre programmiertechnisch viel zu umständlich und würde der Performance wohl so stark in die Suppe spucken, dass diese eine zweite Schüssel bräuchte. Wir lösen das Problem, indem wir umdenken:
Rotation!
Die Idee ist so einfach wie gut. Nehmen wir zum Beispiel zwei Punkte auf einer Geraden. Dann rotieren wir die Gerade um den Ersten Punkt und den zweiten Punkt natürlich mit. der Abstand zwischen dem alten und dem neuen zweiten Punkt ist abhängig von Rotation und Abstand zum Ersten Punkt. Das klingt komplizierter als es eigentlich ist.Entfernung der beiden zweiten Punkte in Abhängigkeit zum Radius |
Wie wir das ganze ins dreidimensionale umsetzen können, erkläre ich jetzt.
Umsetzung
Endergebnis
Letztendlich sollten wir etwa so etwas heraus bekommen: (FoD_det = Genauigkeit, FoD_str = Blurstärke gesamt)
glPushMatrix();
//hier kann die Szenerie noch an die richtige Stelle verschoben werden,
//falls gewünscht.
glClear(GL_ACCUM_BUFFER_BIT); //Accum Buffer leeren
for i := 0 to FoD_det do
begin
if (i > 0) and (FoD_str = 0) then break; //falls die verwacklungsstärke = 0 ist, wird die szene nur einmal gerendert
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glPushMatrix();
//verwackeln
if i <> 0 then
begin
glTranslatef(Cam.focus.x,Cam.focus.y,Cam.focus.z);
glRotatef(-Cam.rot.y,0,1,0);
if i = 1 then glRotatef(FoD_str,-1,0,0);
if i = 2 then glRotatef(FoD_str,0.5,-0.5,0);
if i = 3 then glRotatef(FoD_str,0.5,+0.5,0);
glRotatef(Cam.rot.y,0,1,0);
glTranslatef(-Cam.focus.x,-Cam.focus.y,-Cam.focus.z);
end;
Scene.Render; //Szenerie darstellen
glPopMatrix();
//zum Accum Buffer hinzufügen
if FoD_str = 0 then
glAccum (GL_ACCUM, 1)
else
glAccum (GL_ACCUM, 1/(FoD_det+1));
end;
//In den Accum Buffer gerendertes zurückgeben
glAccum (GL_RETURN, 1.0);
glFlush();
glPopMatrix();