Wassershader

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Halan
Beiträge: 73
Registriert: 22.01.2005, 21:47
Benutzertext: programmiersüchtig
Echter Name: Kai Mast
Wohnort: Freak City
Kontaktdaten:

Wassershader

Beitrag von Halan »

Ahoi,

um ein bisschen in das Thema Shader bzw in meinem Fall GLSL reinzukommen würde ich gerne einen Wassershader programmieren.

Die Geometrie für das wasser ist im Prinzip nur eine Flache Ebene die mit einer vernebelten Version des Untergrundes gerendert wird und dazu einer Normalmap die im Verlauf der Zeit gescrollt werden sollen.

Kennt jemand ein gutes Tutorial für fog-basiertes Wasser? Bzw ein generelles Tutorial für Nebeleffekte, soll man ja sowieso nicht mehr über die fixed-function Pipeline machen.

gruß,
Halan
Benutzeravatar
Schrompf
Moderator
Beiträge: 5047
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: Wassershader

Beitrag von Schrompf »

Wenn Du Zugriff auf den DepthBuffer oder die PerPixel-Tiefe hast, kannst Du einfach die Tiefendifferenz Wasseroberfläche zu Hintergrund benutzen. Jag die durch eine Exponentialfunktion der Marke (1 - e^(-faktor * tiefe)) und Du hast die natürliche Nebelstärke gut hinbekommen.

Ohne Tiefe wird's kniffliger. Du könntest beim Rendern des Hintergrundes eine schlichte Schichtnebel-Formel anwenden. Ich hab das irgendwann mal selbst ausgeformelt, aber seitdem nie wieder benutzt, weil die PerPixel-Tiefe auch für viele andere Sachen notwendig war und ich die deswegen immer da hab. Und ich rate dazu, das dann im PixelShader zu berechnen. Ich hab's damals im VertexShader gemacht und habe dadurch einige hässliche Ecken bekommen.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Halan
Beiträge: 73
Registriert: 22.01.2005, 21:47
Benutzertext: programmiersüchtig
Echter Name: Kai Mast
Wohnort: Freak City
Kontaktdaten:

Re: Wassershader

Beitrag von Halan »

Schrompf hat geschrieben:Wenn Du Zugriff auf den DepthBuffer oder die PerPixel-Tiefe hast, kannst Du einfach die Tiefendifferenz Wasseroberfläche zu Hintergrund benutzen. Jag die durch eine Exponentialfunktion der Marke (1 - e^(-faktor * tiefe)) und Du hast die natürliche Nebelstärke gut hinbekommen.
Das Ergibt alles schon irgendwie Sinn. Aber wie greife ich denn auf den Depth Buffer (bzw auch auf den Frame Buffer) von einem Fragment Shader aus zu? Bin da wie gesagt noch nicht so vertieft..
starvald
Beiträge: 31
Registriert: 16.04.2010, 17:20
Wohnort: Heppenheim

Re: Wassershader

Beitrag von starvald »

Hi,

das ist ganz einfach: Im Vertex-Shader hast Du wahrscheinlich so etwas stehen wie Pos = IN.Pos * WorldViewProjection. Den VS-Code erweiterst Du im eine Zeile ViewPos = IN.Pos * WorldView. Die Variable ViewPos reichst Du dann über eine TEXCOORD[x] an den PixelShader weiter.

Wichtig ist, dass Du nur mit der View Matrix multipliziert und nicht noch mit der Projektionsmatrix, da letztere die Tiefenwerte nicht-linear abbildet und eine ungleichmässige Genauigkeit hat. Wenn Du es so machst wie ich es sage, hast Du eine lineare Genauigkeit und Tiefenwerte im Intervall [NearPlane, FarPlane].

Im Pixel Shader erhälst Du dann deine Tiefe mit float fDepth = IN.ViewPos.z und steckst Sie in die Fog-Formel. Alternativ kannst Du noch normalisieren in den Wertebereich [0,1]: float fDepthNorm = IN.ViewPos.z / (FarPlane-NearPlane).

Best,
Nicolas
Halan
Beiträge: 73
Registriert: 22.01.2005, 21:47
Benutzertext: programmiersüchtig
Echter Name: Kai Mast
Wohnort: Freak City
Kontaktdaten:

Re: Wassershader

Beitrag von Halan »

Hab jetzt erstmal angefangen mich in OGRE wieder an Shader ranzustasten mit einen ganz einfachen Besipiel.

Als fragment Shader habe ich

Code: Alles auswählen

void main(void)
{
    // Setting Each Pixel To Red
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
Das funktioniert auch. Wenn ich jetzt aber als Vertexshader folgendes setze Verden manche Vertices falsch angezeigt...

Code: Alles auswählen

void main()
{
    // Transforming The Vertex
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
Das ist ja eigntlich nur ein HelloWorld-Beispiel von GLSL. Mach ich was falsch oder liegts vielleicht an meinen Treibern oder so?
Benutzeravatar
Ingrater
Establishment
Beiträge: 103
Registriert: 18.04.2007, 21:52

Re: Wassershader

Beitrag von Ingrater »

Was heißt falsch angezeigt? Ein screenshot wäre hilfreich.
Warscheinlich verwendet OGRE die buildin variablen von GLSL nicht mehr da diese in der zwischenzeit deprecated sind.
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4273
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Wassershader

Beitrag von Chromanoid »

Ein guter Artikel dazu: http://www.gamedev.net/page/reference/i ... fect-r2642 (bin ich übrigens über die JME3 drauf gestoßen http://jmonkeyengine.org/2011/01/15/new ... yengine-3/ dort wurde die Technik noch etwas angepasst um z.B. ohne Positions-Textur auszukommen)
Halan
Beiträge: 73
Registriert: 22.01.2005, 21:47
Benutzertext: programmiersüchtig
Echter Name: Kai Mast
Wohnort: Freak City
Kontaktdaten:

Re: Wassershader

Beitrag von Halan »

starvald hat geschrieben:das ist ganz einfach: Im Vertex-Shader hast Du wahrscheinlich so etwas stehen wie Pos = IN.Pos * WorldViewProjection. Den VS-Code erweiterst Du im eine Zeile ViewPos = IN.Pos * WorldView. Die Variable ViewPos reichst Du dann über eine TEXCOORD[x] an den PixelShader weiter.
Danke für den Tipp. Aber genau das will ich ja eigentlich nicht machen. Ich will ja wissen wie "tief" das Wasser an einer bestimmten Stelle ist und abhängig davon die Transprenz im Fragment Shader anpassen.

Btw: Den Shader hab ich jetzt übrigends doch zum laufen bekommen. Lag wohl an einem falschen Material-Script.
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4273
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Wassershader

Beitrag von Chromanoid »

Du könntest aus dem dephbuffer die World Position berechnen. So machen die das bei der JME3. Ansonsten müsstest du die WorldPosition ja genauso durchreichen können (z.B. über ein Farbregister). Musst dann halt nur mit den entsprechenden Matrizen multiplizieren (so wie ich das mir gerade vorstelle einfach nur WorldTransform des jew. Models).
Benutzeravatar
Schrompf
Moderator
Beiträge: 5047
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: Wassershader

Beitrag von Schrompf »

Du brauchst ja nun üblicherweise nicht die "Tiefe" des Wassers an der Stelle, sondern die Strecke ab der Wasseroberfläche bis zum Grund dahinter. Die könntest Du einfach berechnen, indem Du (ab DX10-Hardware) den Depth Buffer an der Bildschirmposition samplest oder indem Du in einem vorherigen Pass die Tiefe ausrenderst. Deferred Renderer haben diese Information schon automatisch da, Forward Renderer aber meistens auch.

Wenn Du wirklich tatsächlich ganz sicher und nicht nur vermutlich die Wassertiefe brauchst, also den Abstand des Bodens zur Wasseroberfläche in senkrechter Richtung, dann wirst nach meinem Verständnis nicht drumrumkommen, die als Zusatzinformation mit reinzureichen. Entweder als zusätzliche Textur-Komponente oder pro Vertex. Ich behaupte aber, das Du das nicht brauchst.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4273
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Wassershader

Beitrag von Chromanoid »

Hab eben mal geschaut. So holen die bei dem JME3 Shader die WorldPosition aus Tiefe und Bildposition:

Code: Alles auswählen

vec3 getPosition(in float depth, in vec2 uv){
    vec4 pos = vec4(uv, depth, 1.0) * 2.0 - 1.0;
    pos = m_ViewProjectionMatrixInverse * pos;
    return pos.xyz / pos.w;
}
Benutzeravatar
Schrompf
Moderator
Beiträge: 5047
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: Wassershader

Beitrag von Schrompf »

Und woher bekommt er die Tiefe?
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4273
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Wassershader

Beitrag von Chromanoid »

Naja wie du schon sagtest muss man dazu den Depthbuffer fragen. Das setzt natürlich voraus, dass man noch keine Wasseroberfläche (mit Z-Buffer) gerendert hat, wenn man das überhaupt will. Bei JME3 wird Forward-Rendering benutzt und nach dem normalen Rendervorgang der Depth-Buffer für evt. PostProcessing-Effekte in eine Textur kopiert.
BTW ich möchte noch anmerken, dass ich mich kaum mit Grafikprogrammierung beschäftige, es nur so wiedergebe wie ich es verstanden habe und selbst noch nicht all zu viele Shader gebastelt habe.
Benutzeravatar
Schrompf
Moderator
Beiträge: 5047
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: Wassershader

Beitrag von Schrompf »

Hm, genau dieses DepthBuffer-In-Textur-Kopieren ist der spannende Teil, finde ich. Das geht nach meinem Wissen erst ab DX10 verlässlich. Es kann aber sein, dass die JME3 OpenGL verwendet und es da Extensions gibt, die dass schon für DX9-Level-Hardware anbieten.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4273
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: Wassershader

Beitrag von Chromanoid »

Also sie benutzt OpenGL. Habe eben mal geschaut, die benutzen: glBlitFramebufferEXT bzw GL_EXT_framebuffer_blit
Halan
Beiträge: 73
Registriert: 22.01.2005, 21:47
Benutzertext: programmiersüchtig
Echter Name: Kai Mast
Wohnort: Freak City
Kontaktdaten:

Re: Wassershader

Beitrag von Halan »

Schrompf hat geschrieben:Hm, genau dieses DepthBuffer-In-Textur-Kopieren ist der spannende Teil, finde ich. Das geht nach meinem Wissen erst ab DX10 verlässlich. Es kann aber sein, dass die JME3 OpenGL verwendet und es da Extensions gibt, die dass schon für DX9-Level-Hardware anbieten.
Alles klar. Danke für den Tipp. Muss ich mal gucken ob das in OGRE irgendwie möglich ist. Mit einfacher Transparenz sieht es aber eigentlich auch ganz gut aus. Glaube ich lass das erstmal so.
Benutzeravatar
Schrompf
Moderator
Beiträge: 5047
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: Wassershader

Beitrag von Schrompf »

Was ich noch empfehlen kann, ist der Fresnel-Term. Google mal danach. Der beschreibt ganz schlicht die Tatsache, dass die Durchsichtigkeit der Wasseroberfläche mit dem Blickwinkel variiert. Wenn man flach auf's Wasser schaut, sieht man quasi nur die Spiegelungen, schaut man steiler auf die Wasseroberfläche, kann man zunehmend besser durchgucken. In der schlichten Variante müsstest Du also nur den Alpha-Wert des ausgegebenen Pixels in Abhängigkeit vom Punktprodukt zwischen Normale und Blickrichtung verändern.

Ich habe dabei übrigens festgestellt, dass das alles erst so richtig cool kommt, wenn man im linearen Farbraum arbeitet. Der ganze AlphaBlending-Kram, die banalen dot()-Beleuchtungsformeln und was weiß ich noch sehen plötzlich irgendwie greifbar aus. Ist aber etwas fortgeschrittener, also schau Dir das später nochmal an.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Wassershader

Beitrag von Krishty »

Dazu sei genannt – falls noch nicht geschehen (habe nicht alles gelesen) – einer der größten Fehler: Stinknormales Alphablending für Wasser zu nehmen.

Dass man durch viel Wasser weniger sehen kann als durch wenig Wasser, ist ein Faktor, also multiplikativ. (Und der Faktor selber ist exponentiell.) Spiegelungen auf der Oberfläche sind hingegen additiv. Darum muss man das Alphablending auch schön auf Bodenfarbe × „Trübungsfaktor“ + Spiegelung stellen (gilt übrigens auch für alle anderen transparenten Objekte, die es gibt; insbesondere für Glas). Falls man das nicht macht, bringt einem auch kein linearer Farbraum mehr was … weil dann die Helligkeit des Wassers Einfluss darauf hat, wie viel es spiegelt, und es schrecklich aussieht. Siehe Fensterscheiben in CS 1.6.

Gruß, Ky
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 5047
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: Wassershader

Beitrag von Schrompf »

Ein guter Hinweis. Ich habe vor geraumer Weile alles auf Premultiplied Alpha umgestellt. Damit kann man dann z.b. hier beim Wasser die Spiegelungen additiv anbringen und unabhängig davon dem Untergrund exponentiell ausgrauen.

Was genau ist eigentlich vom Fresnel-Term betroffen? Die Menge an Licht, die von unterhalb der Wasseroberfläche durchdringt? Oder die Menge an Licht von oberhalb der Wasseroberfläche, die an der Oberfläche reflektiert wird? Ich werde leider aus dem Wikipedia-Eintrag dazu nicht schlau, auch wenn ich inzwischen vermute, dass es der Teil von unterhalb der Wasseroberfläche ist.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Wassershader

Beitrag von Krishty »

Weiß ich nicht, da ich die Fresnelformel nie verstanden habe (die war ja auch bei meiner Glare-Simulation ein Schwachpunkt).

Allerdings ist die Wasseroberfläche von unten genau so reflektiv wie von oben, das heißt:

Wenn die Spiegelungen bei frontaler Draufsicht auf die Oberfläche am schwächsten sind, und dann mit flacher werdendem Winkel bis zur Totalreflektion stärker werden, dann gilt unterwasser exakt das gleiche und darum für Licht, das vom Grund kommt, genau das umgekehrte (Transparenz = 1 - relative Reflektivität von oben).

Wenn die Spiegelungen bei frontaler Draufsicht auf die Oberfläche am schwächsten sind, ist der Grund am deutlichsten erkennbar, da am wenigsten von seinem Licht gespiegelt und zum Grund zurückgeworfen wird. Wenn die Spiegelung maximal ist, kannst du keinen Grund mehr erkennen, weil auch das Licht, das vom Grund in deine Richtung kommt, an der Oberfläche total ins Wasser zurückreflektiert wird.

Meine persönliche unqualifizierte Mutmaßung; mein Physiklehrer würde jetzt ausrasten und brüllen „Ich hab’ ja gesagt dass aus dir nichts wird“ ;)


Aber Premultiplied Alpha ist ein Segen <3
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: Wassershader

Beitrag von eXile »

Krishty hat geschrieben:Weiß ich nicht, da ich die Fresnelformel nie verstanden habe (die war ja auch bei meiner Glare-Simulation ein Schwachpunkt).
Fresnel-Effekt ist nicht das gleiche wie Fresnel-Diffraktion. ;)

Der Fresnel-Effekt entsteht vielmehr durch die korrekte Betrachtung der Polarisation des Lichts; dies hängt somit mit der Anschauung des Lichts als Welle zusammen. Im Falle eines Dielektrikums, d.h. eines Materials, welches zu beiden Seiten der Reflexion / Transmission keine Energie absorbiert, können vereinfachte Formeln gefunden werden, denn die Relexionsindizes der Materialien sind dann reellwertige Zahlen, und keine komplexen Zahlen. Als Dielektrika gelten z.B. Glas oder hier auch Wasser.

Bei nicht dielektrischen Materialien wird das ganze ne Ecke schwieriger, da man dann eigentlich komplexwertige Reflexionsindizes betrachten muss (und dementsprechend auch eine komplexwertige Fresnelformel benutzen muss). Da das zu kompliziert ist, benutzt man in der Regel für solche Fälle die (krasse) Schlick-Approximation der komplexwertigen Fresnelformel, welche auch für die reellwertige Fresnelformel funktioniert.

Eine Implementation mit Schlick-Approximation findet man z.B. hier, wobei die die Reflektanz in Normalenrichtung merkwürdigerweise fresnelBias nannten, warum auch immer.
Halan
Beiträge: 73
Registriert: 22.01.2005, 21:47
Benutzertext: programmiersüchtig
Echter Name: Kai Mast
Wohnort: Freak City
Kontaktdaten:

Re: Wassershader

Beitrag von Halan »

Krishty hat geschrieben:Darum muss man das Alphablending auch schön auf Bodenfarbe × „Trübungsfaktor“ + Spiegelung stellen
Aber soweit ich weiss werden Farben ja abhängig von der Tiefe des Wassers verschieden verändert. Das heisst ich brauche wieder die Tiefe.
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Wassershader

Beitrag von Krishty »

Nur die Trübung ändert sich; Bodenfarbe und Spiegelung bleiben gleich. Natürlich kommen da noch andere Effekte dazwischen wie, dass tiefes Wasser schlechter (und blauer) ausgeleuchtet ist, Wasser Licht zum Betrachter streut, und so … die haben aber mit dem Blending an sich nichts zu tun.

Was die Tiefe angeht: im Grunde musst du „nur“ wissen, wie viele Meter dein Blick durchs Wasser geht, und dann TrübungEinesMetersWassersRGB ^ Tiefe rechnen, um den Faktor für die Trübung zu erhalten. Wie man das nun speziell mit der Brechung und den anderen Effekten zusammenbackt, kann ich so nicht sagen.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Jörg
Establishment
Beiträge: 296
Registriert: 03.12.2005, 13:06
Wohnort: Trondheim
Kontaktdaten:

Re: Wassershader

Beitrag von Jörg »

Krishty hat geschrieben:
Allerdings ist die Wasseroberfläche von unten genau so reflektiv wie von oben[...]

Meine persönliche unqualifizierte Mutmaßung; mein Physiklehrer würde jetzt ausrasten und brüllen „Ich hab’ ja gesagt dass aus dir nichts
Ja das wuerde er. Snellius, Totalreflektion und so ;)
Antworten