Wasser-Brechung
-
Hallo,
ich bin momentan daran eine Wasserobefläche zu programmieren. Dafür benutze ich eine Ebene, eine reflection-texture und eine refraction-texture. Der Teil mit der Reflektion funktioniert wunderbar und ist im Internet ausführlich dokumentiert.
Mit der Brechung/refraction habe ich jetzt aber meine Probleme, da ich dazu nicht die Infos finde, welche ich benötige.1. Die refraction-texture rendere ich momentan einfach indem ich die Szene aus derselben Kamera-Position nur mit einer zusätzlichen Clipping-Plane dazu render.
Muss man um den richtigen Brechungseffekt zu erreichen die Position der Kamera ändern, in etwa so wie man es ja auch bei der Reflektion macht?2. Die Fragment-Farbe der Lichtbrechung ermittel ich momentan so:
vec3 refraction = normalize(refract(vertex, normal, 1.0/1.33)); vec2 projectiveTextureCoordinates = vec2(gl_FragCoord.s / screenWidth, gl_FragCoord.t / screenHeight); vec4 refractionColor = texture(refractionSampler, projectiveTextureCoordinates + refraction.xy/50.0);
Daran stören mich zwei Sachen. Zum einen teile ich die refraction-Variable durch 50.0, einfach weil es richtig aussieht. Jedoch möchte ich die Lichtbrechung so weit es geht einigermaßen physikalisch korrekt haben. Wie ist da die richtige Vorgehensweise? Zum anderen gibt es durch die Verschiebung der Texturkoordinaten am Rand des Bildschirms hässliche Artefakte. Das Bild scheint dort dann gestreckt. Wie beuge ich diesem Problem vor?
Ich hoffe mir kann jemand die eine oder andere Frage beantworten. Schonmal Danke im voraus
-
Ich sag mal wie ich das machen würde^^
Wenn man auf eine Wasseroberfläche schaut, dann wird der Kamerastrahl so wie hier gebrochen:
http://www.grund-wissen.de/physik/_images/lichtbrechung.png
Ich würde die Kamera einfach in Verlängerung des gebrochenen Strahles auf die Wasseroberfläche schauen lassen. Per Stencil-Puffer würde ich den Zeichenbereich so einschränken, dass ein Rechteck, das Becken/Den Wasseroberfläche umschließt. Das so geränderte Bild kommt in eine Textur.
Dieses Rechteck liegt parallel zum Bildschirm. Ist also im Prinzip ein ganz einfaches 2D-Rechteck.
Wenn du das jetzt nicht verstehst wie ichs meine, dann kann ich ja mal ein Bild mit Paint malen.
-
Ok, also wie ich das verstehe würdest du einfach die Kamera um den Brechungswinkel rotieren, die Szene aufzeichnen und dann einfach das Rechteck perspektivisch Korrekt abbilden? Das würde ich noch hinbekommen^^
Hast du den Stencilbuffer vorgeschlagen, um nicht unnötig viel zu rendern oder hattest du da noch einen anderen Hintergedanken?
Aber wenn ich das so mache wird dabei noch nicht die gewellte Wasseroberfläche berücksichtigt. Ich habe mir das schon was überlegt, wie ich die Verschiebung auf der Textur anhand der Wassertiefe berechne (eine depth-texture render ich eh mit), allerdings hatte ich bisher noch nicht die Zeit diesen Gedanken auszuformulieren und werde das die nächsten Tage nachholen.
Was habt ihr denn sonst für Ideen die Oberflächenstruktur zu berücksichtigen? (Oberflächennormale und Wassertiefe habe ich gegeben)
-
Den Stencil-Puffer hab ich, damit man alles, was außerhalb des Beckenrandes liegt nicht mit rendert. Wenn eine Textur erstellt werden soll, welche das gebrochene Bild zeigt, dann muss diese ja nur das enthalten, was alles unter Wasser liegt, was also innerhalb des Beckenrandes liegt.
Deine Idee dass du einfach unterschiedliche UV-Koordinaten anhand der Wassertiefe ausließt klingt für mich bissel wie Parallax-Mapping(Abgewandelt natürlich).
Wenn bei dir im Wasser aber ein Objekt steht, wie willst du dass da machen?
Wenn du als Beckenboden/Wasserseeboden einfach nur eine gerade Fläche hättest, dann kann ich das ja noch verstehen, dass man dort mit versetzten UV-Auslesen beim Boden das Brechen machen kann. Aber sobald dort ein Stein am Boden liegt, dann wirds schwierig.
Das man bei meiner Variante keine Wasserwellen hat, ist richtig. Man könnte die vielleicht höchstens hineinfaken, indem man bei der erstellten Brechungstextur, welche durch rendern entsteht, noch per Normalmapping oder so wellen drauf bügelt. Wenn du verstehst was ich meine^^
-
Mit dem Parallax-Mapping hast du ein interessantes Stichwort gegeben. Die Ungenauigkeiten bei einem unebenden Boden im Wasser ist natürlich gegeben, aber ich guck mal wie sehr das ein Problem wird, vor allem an steilen Kanten unter Wasser. Aber vielleicht sieht man den fehler gar nicht so stark
Ich hab auch noch mal ein bisschen weitergesucht und bin dabei auf Parallax-Occlusion-Mapping gestoßen. So weit wie ich das verstanden habe, sollte das das Problem mit den Unebenheiten auf dem Boden lösen. Allerdings kommt mir das etwas over-the-top vor, nur um eine Lichtbrechung zu simulieren. Aber weiß jemand wie sehr das ganze ins Gewicht fällt im Vergleich zu der Zeit, die es braucht um die Szene zwei mal neu zu rendern? (Übrigens gute Idee mit dem Stencil-Buffer, jedoch hab ich mir da noch absolut keine Gedanken gemacht, wie man diesen kreiert und berechnet)XMAMan schrieb:
Das man bei meiner Variante keine Wasserwellen hat, ist richtig. Man könnte die vielleicht höchstens hineinfaken, indem man bei der erstellten Brechungstextur, welche durch rendern entsteht, noch per Normalmapping oder so wellen drauf bügelt. Wenn du verstehst was ich meine^^
Wär diese Art von Normal-Mapping nicht einfach eine noch laxere und ungenauere Version des Parallax-Mappings?
-
Wenn du eine Bumpmap hast, welche ein Wellenmuster enthält, und diese einfach auf jede X-Beliebe Brechungstextur drauf machst, dann ist das auf jeden Fall ungenauer, als wenn du mit richtig berechneten parallax-Mapping arbeitest.
Normalerweise sieht man Wellen aber in der Brechung eher durch Kaustiken(Helle Lichtbündelungen).
Das du bei der Reflexion die Wellen beachten muss erscheint mir von daher sinnvoll, um es realistisch aussehen zu lassen.
Bei der Brechung brauchst du aber die Brechungstextur einfach nur hiermit
Multiplizieren. Oder willst du wirklich, dass man den Boden des Beckens verzehrt (also nicht nur einfach gebrochen) sieht?
Wenn du wirklich eine Verzehrung in Form eines Wellenmusters willst, kannst du ja immer noch zusätzlich neben den versetzen UV-Auslesen aufgrund der Brechung über eine versetzte UV-Auslesung aufgrund eines Wellenmusters nachdenken.
Wenn ich das in Gedanken so mache, dann musst du beim Berechnen der UV-Koordinaten der Beckenboden-Textur für jeden Pixel einen Strahl zwischen Wasseroberfläche, und Grund senden, wenn du es wirklich realistisch willst. Überlege dir einfach mal, wie ein Raytracer das macht.
Es könnte etwas viel für den Pixelshader werden. Von daher geht ja immer noch, dass du einfach ein festes Wellenmuster zur UV-Verzehrung nimmst.
-
Öhm....
Ich möchte mich kurz vorstellen, da ich neu hier bin und generell neu - mich aber speziell für dieses Thema "Design" interessiere... nunja eigentlich für die Algorithmen und die Mathematik hierhinter...
Ohne jetzt genaueres Hintergrundwissen zu haben, bzw. mich würde das auch interessieren:
Du hast Recht damit das du das Licht reflektiert und refraktiert wird und zwar wird es refraktiert in dem Moment in dem ja der kritische Winkel überschritten wird, das Objekt WIRD verzerrt und die Wellen spielen eine Rolle... wäre es nicht möglich in genau diesem Fall (wenn überschritten) den Vektor schlichtweg um const*variablenfaktor zu versetzen?Oder ist die Frage zu blöd für den Anfang? ^^
PS: Hoppala hab erst jetzt auf das Erstellungsdatum geachtet! Bitte darum, das zu verzeihen!
-
DasMensch schrieb:
.. und zwar wird es refraktiert in dem Moment in dem ja der kritische Winkel überschritten wird...
das ist nicht korrekt, es gibt keinen kritischen winkel ab dem refraktiert wird, es wird immer refraktiert, wie sehr haengt dabei sowohl vom winkel zwischen oberflaeche und blickrichtung, und den material coefizienten, in dem fall wohl luft und wasser ab.
-
Ich glaube 'DerMensch' meint mit kritischen Refraktionswinkel die Totale Reflexion.
Bei den Fresnelformeln (http://de.wikipedia.org/wiki/Fresnelsche_Formeln)
wird ganz gut beschrieben, wie viel Licht reflektiert und gebrochen wird. Da steht auch was zur Totalreflexion.