Wasser Shader mit OpenGL

Ein Wasser Shader mit OpenGL

#OpenGL#C#Projekte#Bachelorstudium#Studium
In einem Modul in meinem Bachelorstudium gab es ein Animationsprojekt, bei dem wir ein kurzes Video mit OpenGL rendern sollten. Ich entschied mich dafür, mich mit prozeduraler Geometrie und Raymarching zu beschäftigen und so einen Wasser Shader zu erstellen.

Implementierung

Raymarching

Das gesamte Video wird über Raymarching generiert:

float ray(vec3 ro, vec3 rd, out vec4 col, bool flip){ float t = 0.; float eps = 0.001; uint steps = 100; while(steps>0 && t<FAR_PLANE){ vec3 p = ro + t*rd; float dist = sdTest(p, col, flip); if (dist<eps){ break; } t += dist; steps --; } if (t>= FAR_PLANE){ t = -1.0; } return t; }

Prozedurale Geometrie

Dazu werden signed distance functions (SDFs) verwendet, um die Geometrie zu beschreiben. Ein simples Beispiel ist die SDF für einen Quader: float quader(vec3 p, vec3 b){ vec3 value = abs(p)-b; if(value.x<0.){ value.x = 0.; } if(value.y<0.){ value.y = 0.; } if(value.z<0.){ value.z = 0.; } return length(value); } Diese SDF habe ich rekursiv aufgerufen, um komplexe Strukturen zu erzeugen. So habe ich eine abstrakte Darstellung von einem Boot generiert.float recursiveCube(vec3 pos, float edge){ float ret = 10000; vec3 cPos = pos; float cEdge = edge; ret = cube(pos, edge); for(int i=0; i<10; i++){ float mainCube = cube(cPos, cEdge); float sideoffset = cEdge+cEdge*0.75; cPos = cPos-vec3(0,sideoffset,0); cEdge = cEdge*0.75; float smallCube = cube(cPos, cEdge); ret = min(mainCube, min(smallCube, ret)); } return ret; }

Wellen

Dann habe ich die Oberflächen des Würfels mit einer Funktion kombiniert, um die Quader wellig zu machen. Dabei handelt es sich um Gerstner-Wellen:

vec3 gerstner(vec3 position, float wave_height , float wave_length, float speed, vec2 direction){ vec2 d = normalize(direction); float k = M_PI*2.0f / wave_length; float f = k * (dot(position.xz, d)-uTime*speed); float y = wave_height*sin(f); float x = wave_height * cos(f) * d.x; float z = d.y* wave_height*sin(f); vec3 wave = vec3(x, y, z); return wave; }

Sonstiges

Zur Dekoration habe ich ein paar Kakteen auf dem merkwürdigen Boot platziert, die wie Segelmasten aussehen sollen. Außerdem habe ich eine simple Datenstruktur definiert, um die einzelnen Objekte in meiner Szene zu speichern, sodass ich die Objekte auch einzeln einfärben und bewegen konnte.

Ergebnis

Das (für den knappen Zeitrahmen meiner Meinung nach halbwegs vorzeigbare Ergebnis) ist das folgende Video:

Kommentare

Noch Fragen?