Tutorial StereoSehen: Unterschied zwischen den Versionen
(Einleitung auf den neusten Stand der Technik angepasst - TFT Monitore für 3D sind heute kein Ding der Unmöglichkeit!) |
K (→Projektionen: Rechtschreibung, Verlinkung) |
||
(2 dazwischenliegende Versionen von 2 Benutzern werden nicht angezeigt) | |||
Zeile 2: | Zeile 2: | ||
[[Bild:Tutorial_Stereo_anaglyph.jpg|center]] | [[Bild:Tutorial_Stereo_anaglyph.jpg|center]] | ||
==Einleitung== | ==Einleitung== | ||
− | Viele Tiere haben mit dem Menschen eins gemein: Zwei Augen. Dies kann unterschiedliche Vorteile haben, etwa in zwei Richtungen gleichzeitig sehen zu können, oder, was viel häufiger ist, um räumlich sehen zu können. Die Welt aus zwei leicht unterschiedlichen Blickwinkeln zu sehen ermöglicht es dem Gehirn Abstände und Geschwindigkeiten besser | + | Viele Tiere haben mit dem Menschen eins gemein: Zwei Augen. Dies kann unterschiedliche Vorteile haben, etwa in zwei Richtungen gleichzeitig sehen zu können, oder, was viel häufiger ist, um räumlich sehen zu können. Die Welt aus zwei leicht unterschiedlichen Blickwinkeln zu sehen ermöglicht es dem Gehirn Abstände und Geschwindigkeiten besser einzuschätzen, als mit einem Auge. Das es uns auch mit einem Auge gelingt, erkennt man dran, dass das in begrenztem Umfang auch bei Fotos gelingt und wenn wir mit einem geschlossenem Auge durch ein Zimmer laufen trotzdem nicht überall anstossen. Das funktioniert sogar so gut, dass Menschen, die nur stark eingeschränkt oder gar nicht räumlich sehen können, dies gar nicht so selten erst bei Routineuntersuchungen von Augenärzten oder im Verlauf ihrer Musterung erfahren. |
An einer Stelle ist es jedoch egal, ob wir räumlich sehen können oder nicht - beim Spielen und Arbeiten am Computer. Aber 3D Spiele wollen doch gerade eines: uns die Welt möglichst realistisch vor Augen führen. Leider hat der Computer meist nur einen Monitor, wir aber zwei Augen... Und damit Good Bye räumliches Sehen? Nein, nein, so einfach dürfen wir uns nicht geschlagen geben. Tatsächlich fallen mir gleich eine Reihe von Möglichkeiten ein: Stereogramme, wie sie eine Zeit lang modern waren, und in vielen Büchern vorkommen: langes Stieren auf stylisch eingefärbte Buchseiten. Bei 3D-Spielen sind 3D-Shutterbrillen beliebt, bei denen jeweils ein Auge abgedunkelt wird, auf dem Monitor für das Auge ein Bild angezeigt und dann gewechselt wird. Zeigt man für jedes Auge ein leicht versetztes Bild an und wechselt die Bilder häufig genug, entsteht für den Betrachter ein 3-Dimensionales Bild der Szenerie. Für diese Technik ist jedoch ein schnell schaltender Monitor von Nöten - Entweder ein Röhrenmonitor oder ein neuer TFT-Bildschirm mit 120Hz Bildwiederholrate. | An einer Stelle ist es jedoch egal, ob wir räumlich sehen können oder nicht - beim Spielen und Arbeiten am Computer. Aber 3D Spiele wollen doch gerade eines: uns die Welt möglichst realistisch vor Augen führen. Leider hat der Computer meist nur einen Monitor, wir aber zwei Augen... Und damit Good Bye räumliches Sehen? Nein, nein, so einfach dürfen wir uns nicht geschlagen geben. Tatsächlich fallen mir gleich eine Reihe von Möglichkeiten ein: Stereogramme, wie sie eine Zeit lang modern waren, und in vielen Büchern vorkommen: langes Stieren auf stylisch eingefärbte Buchseiten. Bei 3D-Spielen sind 3D-Shutterbrillen beliebt, bei denen jeweils ein Auge abgedunkelt wird, auf dem Monitor für das Auge ein Bild angezeigt und dann gewechselt wird. Zeigt man für jedes Auge ein leicht versetztes Bild an und wechselt die Bilder häufig genug, entsteht für den Betrachter ein 3-Dimensionales Bild der Szenerie. Für diese Technik ist jedoch ein schnell schaltender Monitor von Nöten - Entweder ein Röhrenmonitor oder ein neuer TFT-Bildschirm mit 120Hz Bildwiederholrate. | ||
Zeile 17: | Zeile 17: | ||
==Projektionen== | ==Projektionen== | ||
− | Bei der üblichen, perspektivischen Projektion ist die Sache einfach: Man hat ein Auge, einen Öffnungswinkel für die Kamera und die Entfernung für die nahe Clipping-Ebene: | + | Bei der üblichen, perspektivischen Projektion ist die Sache einfach: Man hat ein Auge, einen Öffnungswinkel für die Kamera und die Entfernung für die nahe Clipping-[[Ebene]]: |
[[Bild:Tutorial_Stereo_perspektivisch.png|center]] | [[Bild:Tutorial_Stereo_perspektivisch.png|center]] | ||
− | Beim Stereo-Sehen wird die Sache ein | + | Beim Stereo-Sehen wird die Sache ein wenig komplizierter. Da man mit beiden Augen auf die Projektionsebene Bildschirm schaut, ist diese für beide Augen identisch, jedoch sind die Blickkegel nicht mehr gerade, sondern schief: |
[[Bild:Tutorial_Stereo_stereo.png|center]] | [[Bild:Tutorial_Stereo_stereo.png|center]] | ||
− | Zu allem | + | Zu allem Überfluss können wir unsere Augen auch noch auf eine bestimmte Entfernung ausrichten, d.h. die Ebene, auf die die Augen eingestellt sind, muss nicht der Entfernung der nahen Clippling-Plane entsprechen - das Problem können wir jedoch ganz einfach mithilfe der Strahlensätze lösen. |
<source lang="pascal">... | <source lang="pascal">... | ||
Zeile 115: | Zeile 115: | ||
end; | end; | ||
...</source> | ...</source> | ||
− | |||
==Und Rendern?== | ==Und Rendern?== | ||
Zeile 216: | Zeile 215: | ||
==Kleine Anmerkung am Rande== | ==Kleine Anmerkung am Rande== | ||
− | Nach Fertigstellung des Tutorials wurde ich darauf aufmerksam gemacht, | + | Nach Fertigstellung des Tutorials wurde ich darauf aufmerksam gemacht, dass man um den Einsatz des P-Buffers herumkommt - was Geschwindigkeit und Kompatibilität erhöht. Man muss nur zwischen den glColorMask Befehlen einmal den Tiefenpuffer leeren. In etwa läuft das ganze dann wie folgt: |
private void RenderMono() | private void RenderMono() |
Aktuelle Version vom 12. Oktober 2013, 19:07 Uhr
Inhaltsverzeichnis
Stereo einmal sehen statt hören
Einleitung
Viele Tiere haben mit dem Menschen eins gemein: Zwei Augen. Dies kann unterschiedliche Vorteile haben, etwa in zwei Richtungen gleichzeitig sehen zu können, oder, was viel häufiger ist, um räumlich sehen zu können. Die Welt aus zwei leicht unterschiedlichen Blickwinkeln zu sehen ermöglicht es dem Gehirn Abstände und Geschwindigkeiten besser einzuschätzen, als mit einem Auge. Das es uns auch mit einem Auge gelingt, erkennt man dran, dass das in begrenztem Umfang auch bei Fotos gelingt und wenn wir mit einem geschlossenem Auge durch ein Zimmer laufen trotzdem nicht überall anstossen. Das funktioniert sogar so gut, dass Menschen, die nur stark eingeschränkt oder gar nicht räumlich sehen können, dies gar nicht so selten erst bei Routineuntersuchungen von Augenärzten oder im Verlauf ihrer Musterung erfahren.
An einer Stelle ist es jedoch egal, ob wir räumlich sehen können oder nicht - beim Spielen und Arbeiten am Computer. Aber 3D Spiele wollen doch gerade eines: uns die Welt möglichst realistisch vor Augen führen. Leider hat der Computer meist nur einen Monitor, wir aber zwei Augen... Und damit Good Bye räumliches Sehen? Nein, nein, so einfach dürfen wir uns nicht geschlagen geben. Tatsächlich fallen mir gleich eine Reihe von Möglichkeiten ein: Stereogramme, wie sie eine Zeit lang modern waren, und in vielen Büchern vorkommen: langes Stieren auf stylisch eingefärbte Buchseiten. Bei 3D-Spielen sind 3D-Shutterbrillen beliebt, bei denen jeweils ein Auge abgedunkelt wird, auf dem Monitor für das Auge ein Bild angezeigt und dann gewechselt wird. Zeigt man für jedes Auge ein leicht versetztes Bild an und wechselt die Bilder häufig genug, entsteht für den Betrachter ein 3-Dimensionales Bild der Szenerie. Für diese Technik ist jedoch ein schnell schaltender Monitor von Nöten - Entweder ein Röhrenmonitor oder ein neuer TFT-Bildschirm mit 120Hz Bildwiederholrate.
Bei der im Jahr 2009 neu aufgelebten 3D-Technik in den Kinos kommen entweder die oben beschriebenen Shutterbrillen oder Brillen mit Polarisationsfiltern zum Einsatz.
Eine äußerst alte aber gut funktionierende Technik ist die der Anaglyphe: Dabei muss der Betrachter eine 3D-Brille aufsetzen, die vor jedes Auge einen anderen Farbfilter setzt, etwa rot und grün. Bei der Filmaufnahme werden dann zwei überkreuzt filmende Kameras verwendet.
Der 3D Effekt stellt sich bei den meisten Menschen schnell ein, bei Anderen dauert es ein wenig oder erfordert etwas Übung. Den Effekt gar nicht genießen können üblicherweise nur stark Schielende, Einäugige und Blinde. Eine wesentliche Einschränkung bei, Anaglyphenverfahren ist jedoch, dass das entstehende Bild meist einfarbig, ähnlich einem s/w Film, ist. Der entstehende 3D Effekt gleicht dieses Manko meiner Ansicht nach auf alle Fälle aus - und da wir möglichst Niemanden ausschliessen möchten, unsere Programme zu bestaunen, werden wir unsere Programme sowohl für "normale" Grafikausgabe als auch für 3D-Brillen vorbereiten.
Die 3D-Brille
Jeder der weitermachen möchte, sollte sich spätestens hier eine 3D-Brille besorgen. Diese gibts z.B. beim Optiker und sollte möglichst einen roten und einen grünen Filter besitzen. Zur Not tuts auch rot-blau, ist jedoch wegen den stark auseinanderliegenden Wellenlängen des roten und blauen Lichtes weniger gut geeignet. Einigen Büchern zu optischen Täuschungen liegen ebenfalls Brillen bei. Solltet ihr keine passende, vorgefertigte Brille finden, könnt ihr sie auch mit etwas Pappe oder Karton und Farbfolien aus dem Bastelladen selbst bauen - oder ganz nobel: mit Filtern aus dem Fotoladen statt ordinären Farbfolien.
Projektionen
Bei der üblichen, perspektivischen Projektion ist die Sache einfach: Man hat ein Auge, einen Öffnungswinkel für die Kamera und die Entfernung für die nahe Clipping-Ebene:
Beim Stereo-Sehen wird die Sache ein wenig komplizierter. Da man mit beiden Augen auf die Projektionsebene Bildschirm schaut, ist diese für beide Augen identisch, jedoch sind die Blickkegel nicht mehr gerade, sondern schief:
Zu allem Überfluss können wir unsere Augen auch noch auf eine bestimmte Entfernung ausrichten, d.h. die Ebene, auf die die Augen eingestellt sind, muss nicht der Entfernung der nahen Clippling-Plane entsprechen - das Problem können wir jedoch ganz einfach mithilfe der Strahlensätze lösen.
...
var
zNear, zFar, Oeffnungswinkel, Augenabstand, Zielweite : Single;
...
const
PBufSize = 1024; //Seitenläne des PBuffers
var
SVerh, ROeffnung : Single;
Breitenhaelfte, NeardZielweite : Single;
left, right, top, bottom : Single;
procedure CalcValues;
begin
ROeffnung := DegToRad(Oeffnungswinkel / 2); //Halber Öffnungswinkel in RAD
Breitenhaelfte := zNear * Tan(ROeffnung); //Halbe Breite der Proj. Ebene
NeardZielweite := zNear / Zielweite;
end;
begin
if Opt.Stereo then //Stereo Modus
begin
glViewport(0, 0, ClientWidth, ClientHeight);
//Projektionsmatrix resetten
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
SVerh := ClientWidth/ClientHeight; //Breite zu Höhe
CalcValues;
//Ränder der Projektionsebene für glFrustum
left := - SVerh * Breitenhaelfte - 0.5 *Augenabstand*NeardZielweite;
right := SVerh * Breitenhaelfte - 0.5 *Augenabstand*NeardZielweite;
top := Breitenhaelfte;
bottom := -Breitenhaelfte;
glFrustum(left, right, bottom, top, zNear, zFar);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
//PBuffer erzeugen und aktivieren, wenn noch nicht geschehen
if not Assigned(PBuffer) then
begin
PBuffer := TPixelBuffer.Create(PBufSize, PBufSize, DC, RC, Self);
wglShareLists(RC, PBuffer.RC);
PBuffer.Enable;
InitGl;
end
else
PBuffer.Enable;
glViewport(0, 0, PBufSize, PBufSize);
//Projektionsmatrix resetten
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//Diesmal das Frustum in die andere Richtung schiefstellen(+ statt -)
left := - SVerh * Breitenhaelfte + 0.5 *Augenabstand*NeardZielweite;
right := SVerh * Breitenhaelfte + 0.5 *Augenabstand*NeardZielweite;
top := Breitenhaelfte;
bottom := -Breitenhaelfte;
glFrustum(left, right, bottom, top, zNear, zFar);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
PBuffer.Disable;
end
else
begin
//Normale Ansicht
glViewport(0, 0, ClientWidth, ClientHeight);
//Projektionsmatrix resetten
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//Perspektivische Darstellung
SVerh := ClientWidth/ClientHeight;
CalcValues;
//Hier wird nichts verschoben
left := - SVerh * Breitenhaelfte;
right := SVerh * Breitenhaelfte;
top := Breitenhaelfte;
bottom := -Breitenhaelfte;
glFrustum(left, right, bottom, top, zNear, zFar);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
end;
end;
...
Und Rendern?
Nun müssen wir nur noch zwei Bilder anzeigen. Die einfachste Möglichkeit dürfte sein, ein Bild für das linke Auge in einen PBuffer oder sonstige Textur zu rendern, dann das Bild für das rechte Auge in den Hintergrundpuffer. Der Inhalt des PBuffers wird dann mittels Blending auch in den Hintergrundpuffer gezeichnet und voila. Wir haben zwei verschiedene Bilder auf dem Schirm. Zu beachten ist noch, dass die Farben mittels glColorMask beim Rendern maskiert werden müssen - wir wollen ja für die beiden Augen unterschiedliche Farben anzeigen.
procedure TStereoForm.Render;
procedure RenderScene;
begin
//kein glLoadIdentity am Anfang! Das muss vorher gemacht worden sein -
//für die Augen muss ja bereits verschoben worden sein. Also Achtung.
//Brav mit Push und Pop Matrix arbeiten.
...
end;
var
Error : glUInt;
begin
if (Opt.Stereo) and (Assigned(PBuffer)) then
begin
//Stereo Modus
PBuffer.Enable;
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_DEPTH_BUFFER_BIT or GL_COLOR_BUFFER_BIT);
glLoadIdentity;
glTranslatef(Augenabstand/2, 0, 0);
//linkes Auge bekommt grün und blau - das sollte über Optionen wählbar sein
glColorMask(false, true, true, true);
RenderScene;
PBuffer.Disable;
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_DEPTH_BUFFER_BIT or GL_COLOR_BUFFER_BIT);
glLoadIdentity;
glTranslatef(-Augenabstand/2, 0, 0);
//rechtes Auge bekommt nuir rot
glColorMask(true, false, false, true);
RenderScene;
//Und zusammenblenden
glColorMask(true, true, true, true);
glDepthFunc(GL_ALWAYS);
glMatrixMode(GL_PROJECTION);
glPushMatrix;
glLoadIdentity;
glOrtho(0, 1, 1, 0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
PBuffer.Bind;
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glBegin(GL_QUADS);
glTexCoord2f(1, 0); glVertex2f(1,1);
glTexCoord2f(1, 1); glVertex2f(1,0);
glTexCoord2f(0, 1); glVertex2f(0,0);
glTexCoord2f(0, 0); glVertex2f(0,1);
glEnd();
glDisable(GL_BLEND);
glEnable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
PBuffer.Release;
glMatrixMode(GL_PROJECTION);
glPopMatrix;
glMatrixMode(GL_MODELVIEW);
glDepthFunc(GL_LESS);
end
else
begin
//"Mono" Modus
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_DEPTH_BUFFER_BIT or GL_COLOR_BUFFER_BIT);
glLoadIdentity;
RenderScene;
end;
...
end;
Und 3D-Shutterbrillen?
Wer eine 3D-Sutterbrille und entsprechendes Equipment zuhause hat, kann seine Anwendungen auch für diese anpassen. Einige Grafikkarten haben bereits passende Treiber, die die Ausgabe der Programme automatisch anpassen. Wer das nicht will, sollte sich einmal mit Stereo-OpenGl auseinandersetzen. Bei der dglOpenGl genügt es, den Rendering Context mit der Option opStereo zu erstellen. Mit glDrawBuffer(GL_BACK_LEFT/GL_BACK_RIGHT) kann dann für jedes Auge in einen anderen Puffer gerendert werden.
Abschluss
Ich hoffe euch hat dieser kleine Exkurs gefallen. Vielleicht läuft einem ja mal das eine oder andere Programm über den Weg, wo man die Wahl zwischen Tiefensehen und normaler Ansicht hat - mich würde es jedenfalls freuen, zumal es ja nicht wirklich schwer ist, seine Programme entsprechend anzupassen und es doch ein wesentlich anderes Gefühl der Szene erzeugt, als üblicherweise vor dem Computer. Ich bin jedenfalls gespannt, erwarte mir aber nicht allzuviel - bislang war das Feedback und eure Demos ja sehr bescheiden. Wo ich da nur immer die Motivation hernehme, euch mit ein paar neuen Ideen zu versorgen? ;-D
Euer Delphic
Kleine Anmerkung am Rande
Nach Fertigstellung des Tutorials wurde ich darauf aufmerksam gemacht, dass man um den Einsatz des P-Buffers herumkommt - was Geschwindigkeit und Kompatibilität erhöht. Man muss nur zwischen den glColorMask Befehlen einmal den Tiefenpuffer leeren. In etwa läuft das ganze dann wie folgt:
private void RenderMono() { RenderSettings rs = new RenderSettings(); rs.Mono(RenderPanel.ClientRectangle.Width, RenderPanel.ClientRectangle.Height); GL.Clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT); //Szene Rendern } private void RenderStereo() { GL.Clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT); RenderSettings rs = new RenderSettings(); rs.Stereo(true, RenderPanel.ClientRectangle.Width, RenderPanel.ClientRectangle.Height); GL.ColorMask(1, 0, 0,1); //Szene Rendern rs.Stereo(false, RenderPanel.ClientRectangle.Width, RenderPanel.ClientRectangle.Height); GL.Clear(GL.DEPTH_BUFFER_BIT); GL.ColorMask(0, 1, 1,1); //Szene Rendern if (GL.GetError() != GL.NO_ERROR) { } } private void Render() { if (rc != null) { GL.PushAttrib(GL.ALL_ATTRIB_BITS); GL.ClearColor(0.0f, 0f, 0f, 1f); if (stereo) RenderStereo(); else RenderMono(); rc.SwapBuffers(); GL.PopAttrib(); } }
Die rs.stereo(true/false, ...) Befehle laden die benötigten Matrizen für das linke bzw. rechte Auge.
Dateien
|
||
Vorhergehendes Tutorial: Tutorial_StencilSpiegel |
Nächstes Tutorial: Tutorial_Alphamasking |
|
Schreibt was ihr zu diesem Tutorial denkt ins Feedbackforum von DelphiGL.com. Lob, Verbesserungsvorschläge, Hinweise und Tutorialwünsche sind stets willkommen. |