Die optimale Lösung wäre die Darstellung der transparenten Objekte in einem zweiten Render-Durchgang, nach dem bereits alle nicht transparenten (opaquen) gerendert worden sind. Zur Vermeidung von z-Fighting Problemen müssen die transparenten Objekte mit deaktiviertem Tiefenpuffer gerendert werden. Damit die durch die opaquen Objekte verdeckten Bereiche nicht dargestellt werden, muss darüber hinaus ein Tiefenvergleich mit den Tiefenwerten dieser Objekte durchgeführt werden.
Zu Demonstrationszwecken haben wir das vorangegangene Programmbeispiel um vier volumetrische Nebelwolken erweitert, die wir um den Planeten herum positioniert haben. Gerendert werden die einzelnen Nebelpartikel dieser Wolken mit deaktivierten Tiefenpuffer in einem zweiten Durchgang nach der Darstellung des Planeten.
Wie bereits erwähnt, besteht der eigentliche Trick bei der Partikeldarstellung im Tiefenvergleich zwischen den Tiefenwerten der Erde mit denen der Partikel.
Im Vertex Shader (VolumetricNebula.vert) werden zunächst die World-Space-Vertexpositionen an den Fragment Shader weitergeleitet:
gl_Position = matWorldViewProjection*gs_Vertex;
gs_TexCoord[0] = gs_MultiTexCoord0;
gs_TexCoord[1].x = gl_Position.x;
gs_TexCoord[1].y = gl_Position.y;
gs_TexCoord[1].z = gl_Position.z;
Der eigentliche Tiefenvergleich findet dann im Fragment Shader (VolumetricNebula.frag) statt:
// World-Space-Vertexposition in den Screen Space transformieren:
float tempFloat = 1.0/gl_Position.z;
vec2 ProjectedTexCoord = vec2(0.5*gs_TexCoord[1].x*tempFloat + 0.5,
0.5*gs_TexCoord[1].y*tempFloat + 0.5);
// Tiefenwerte aus dem Renderdurchgang mit den opaquen Objekten auslesen.
float CameraDepth1 = texture2D(CameraDepthTexture, ProjectedTexCoord).w;
float CameraDepth2 = texture2D(CameraDepthTexture, ProjectedTexCoord+
vec2(0.0005, 0.0005)).w;
float CameraDepth3 = texture2D(CameraDepthTexture, ProjectedTexCoord-
vec2(0.0005, 0.0005)).w;
float CameraDepth4 = texture2D(CameraDepthTexture, ProjectedTexCoord+
vec2(-0.0005, 0.0005)).w;
float CameraDepth5 = texture2D(CameraDepthTexture, ProjectedTexCoord-
vec2(-0.0005, 0.0005)).w;
float MinCameraDepth = CameraDepth1;
MinCameraDepth = min(MinCameraDepth, CameraDepth2);
MinCameraDepth = min(MinCameraDepth, CameraDepth3);
MinCameraDepth = min(MinCameraDepth, CameraDepth4);
MinCameraDepth = min(MinCameraDepth, CameraDepth5);
if(MinCameraDepth < 0.0)
MinCameraDepth = 100000.0;
float MaxCameraDepth = CameraDepth1;
MaxCameraDepth = max(MaxCameraDepth, CameraDepth2);
MaxCameraDepth = max(MaxCameraDepth, CameraDepth3);
MaxCameraDepth = max(MaxCameraDepth, CameraDepth4);
MaxCameraDepth = max(MaxCameraDepth, CameraDepth5);
if(MaxCameraDepth < 0.0)
MaxCameraDepth = 100000.0;
float diff = abs(MaxCameraDepth-MinCameraDepth);
// Tiefenvergleich durchführen:
if(diff > 0.5)
gs_FragColor = Brightness*NebulaColor;
else
{
if(MinCameraDepth < gs_TexCoord[1].z-0.125)
discard;
else
gs_FragColor = Brightness*NebulaColor;
}
Hinweis:float tempFloat = 1.0/gl_Position.z;
vec2 ProjectedTexCoord = vec2(0.5*gs_TexCoord[1].x*tempFloat + 0.5,
0.5*gs_TexCoord[1].y*tempFloat + 0.5);
// Tiefenwerte aus dem Renderdurchgang mit den opaquen Objekten auslesen.
float CameraDepth1 = texture2D(CameraDepthTexture, ProjectedTexCoord).w;
float CameraDepth2 = texture2D(CameraDepthTexture, ProjectedTexCoord+
vec2(0.0005, 0.0005)).w;
float CameraDepth3 = texture2D(CameraDepthTexture, ProjectedTexCoord-
vec2(0.0005, 0.0005)).w;
float CameraDepth4 = texture2D(CameraDepthTexture, ProjectedTexCoord+
vec2(-0.0005, 0.0005)).w;
float CameraDepth5 = texture2D(CameraDepthTexture, ProjectedTexCoord-
vec2(-0.0005, 0.0005)).w;
float MinCameraDepth = CameraDepth1;
MinCameraDepth = min(MinCameraDepth, CameraDepth2);
MinCameraDepth = min(MinCameraDepth, CameraDepth3);
MinCameraDepth = min(MinCameraDepth, CameraDepth4);
MinCameraDepth = min(MinCameraDepth, CameraDepth5);
if(MinCameraDepth < 0.0)
MinCameraDepth = 100000.0;
float MaxCameraDepth = CameraDepth1;
MaxCameraDepth = max(MaxCameraDepth, CameraDepth2);
MaxCameraDepth = max(MaxCameraDepth, CameraDepth3);
MaxCameraDepth = max(MaxCameraDepth, CameraDepth4);
MaxCameraDepth = max(MaxCameraDepth, CameraDepth5);
if(MaxCameraDepth < 0.0)
MaxCameraDepth = 100000.0;
float diff = abs(MaxCameraDepth-MinCameraDepth);
// Tiefenvergleich durchführen:
if(diff > 0.5)
gs_FragColor = Brightness*NebulaColor;
else
{
if(MinCameraDepth < gs_TexCoord[1].z-0.125)
discard;
else
gs_FragColor = Brightness*NebulaColor;
}
Für die Ausführung dieses Programmbeispiels muss der Treiber Ihrer Grafikkarte die OpenGL Version 3.3 unterstützen.
Visual C++ 2010: DemoWithOpenGL2010_Tut15