OpenGL Tutorial (Version 3.3) – Planeten-Darstellung, Atmosphäre und Wolken (Download)

Heute werden wir das vorangegangene Programmbeispiel um zwei neue Elemente erweitern und in diesem Zusammenhang unseren Planeten mit einer Atmosphäre und prozedural generierten Wolken umhüllen.
Betrachten wir zunächst die Wolken-Darstellung. Für gewöhnlich umhüllt man den Planeten mit einem oder mit mehreren Wolken-Layern (kugelförmiges 3D-Modell auf das eine Wolkentextur gemappt wird), die sich mit verschiedenen Geschwindigkeiten um den Planeten herumdrehen. Entscheidend für die Optik ist hierbei die Auflösung der Wolkentextur.


Die Auflösung kann jedoch dadurch erhöht werden, dass man die Wolkentextur im Fragment Shader (PlanetaryClouds.frag) zusätzlich mit verschiedenen Wrap-Faktoren (CloudInvDensityValues.x, CloudInvDensityValues.y, CloudInvDensityValues.z) mehrfach ausliest und die Farbwerte entsprechend gewichtet.

vec4 CloudCol = texture(PlanetaryCloudTexture, gs_TexCoord[0].st);

// Hinweis: An den Polen (VertexNormale.y == 1 oder -1; tempFloat == 0)
// soll nur die einfach gewrappte Wolkentextur verwendet werden.

float tempFloat = 1.0-abs(VertexNormale.y);

vec4 CloudCol2 = texture2D(PlanetaryCloudTexture,
                           CloudInvDensityValues.x*gs_TexCoord[0].st);
CloudCol += tempFloat*CloudCol2;

CloudCol2 = texture2D(PlanetaryCloudTexture,
                      CloudInvDensityValues.y*gs_TexCoord[0].st);
CloudCol += tempFloat*CloudCol2;

CloudCol2 = texture2D(PlanetaryCloudTexture,
                      CloudInvDensityValues.z*gs_TexCoord[0].st);
CloudCol += tempFloat*CloudCol2;

CloudCol *= CloudInvDensityValues.w;


Genau wie die Wolken kann auch die Planetenatmosphäre mithilfe eines einfachen Layers dargestellt werden. Der eigentliche Trick besteht jedoch darin, diesen Layer in Abhängigkeit von der Blickrichtung zu schattieren. Blickt man senkrecht auf die Planetenoberfläche hinab, dann ist der Weg, den die von der Oberfläche reflektierten Lichtstrahlen durch die Atmosphäre zur Kamera nehmen, am kürzesten. Blickt man jedoch schräg hinab, dann verlängert sich der Weg der Lichtstrahlen durch die Atmosphäre, wodurch man die Atmosphärenfarbe zunehmend stärker wahrnimmt. Diesen Effekt gilt es im Atmosphären-Shader nachzuahmen (AtmosphericLighting.vert, AtmosphericLighting.frag). Unser Ziel besteht jedoch nicht darin, den Farbverlauf zu berechnen. Stattdessen verwenden wir eine Look-Up-Textur, in welcher der Farbverlauf bereits abgespeichert ist (maximale Intensität im Textur-Zentrum, minimale Intensität an den Textur-Rändern) und berechnen lediglich für jeden Pixel des Atmosphären-Layers die Texturkoordinaten, mit deren Hilfe wir dann auf die gewünschte Texelfarbe zugreifen können. Zeit, uns die Fragment Shader Berechnungen einmal genau anzuschauen:


// Hier wird ermittelt, wie direkt die Atmosphäre von der Sonne angestrahlt
// wird:
float Dot = 3.0*dot(Vertexnormal, negLightDirModelSpace) + 3.0;

// Hier wird ermittelt, ob man senkrecht (Dot2 == 0.9) oder schräg
// (Dot2 => 0) in die Atmosphäre blickt:
float Dot2 = min(0.9, abs(dot(negViewDirectionModelSpace, Vertexnormal)));

// Texturkoordinaten in Abhängigkeit vom Blickwinkel berechnen:
float texCoord = 1.0-0.5*Dot2;

gs_FragColor =
Brightness*Dot*Dot2*(1.0-Dot2)*
               texture2D(PlanetaryAtmosphereTexture, vec2(texCoord, texCoord));



Hinweis:
Für die Ausführung dieses Programmbeispiels muss der Treiber Ihrer Grafikkarte die OpenGL Version 3.3 unterstützen.

Visual C++ 2010: DemoWithOpenGL2010_Tut14