Recently been trying to implement volumetric lighting. The alphaness texture comes out perfectly on Renderdoc, however a strange glitch occurs whenever I either try to directly render the texture through a quad to the screen, or through multiplying the alphaness component with my regular texture. A strange static pattern (as shown in the image below) appears on the texture. The texture also periodically turns completely black, and in some frames the image comes out perfectly.

Strange static pattern when drawing texture

The volumetric lighting texture is rendered to a framebuffer with the settings below:

' Configure God Rays Buffer
' -------------------------
godRaysFramebuffer = GL.GenFramebuffer()

' Create color buffers
GL.BindFramebuffer(FramebufferTarget.Framebuffer, godRaysFramebuffer)
currentFrameTex = GL.GenTexture()
GL.BindTexture(TextureTarget.Texture2D, currentFrameTex)
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1)
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, All.MirroredRepeat)
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, All.MirroredRepeat)
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, All.Nearest)
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, All.Nearest)
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.R16f, resolutionWidth,
              resolutionHeight, 0, PixelFormat.Red, PixelType.Float, IntPtr.Zero)
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0,
                        TextureTarget.Texture2D, currentFrameTex, 0)

Dim attachments() As Integer = {FramebufferAttachment.ColorAttachment0}
GL.DrawBuffers(attachments.Length, attachments)

The alphaness texture, from Renderdoc, is shown below:

Renderdoc alphaness texture

The fragment shader which samples from the god rays texture (my HDR shader) is shown below. When I comment out the * texture(godRaysTex, TexCoords).r it renders perfectly, however without the god rays.

#version 440 core

out vec4 out_color;

in vec2 TexCoords;
in vec3 vPos;

uniform sampler2D hdrBuffer;
uniform sampler2D godRaysTex;

uniform float exposure;

void main() {             
    const float gamma = 1.8;
    vec3 hdrColor = texture(hdrBuffer, TexCoords).rgb * texture(godRaysTex, TexCoords).r;

    // Exposure tone mapping
    vec3 mapped = vec3(1.0) - exp(-hdrColor * exposure);
    // Gamma correction 
    mapped = pow(mapped, vec3(1.0 / gamma));

    out_color = vec4(mapped, 1.0);

Here is my volumetric lighting shader:

#version 440 core

uniform vec2 lightPositionOnScreen;
uniform sampler2D occlusionTex;

const int NUM_SAMPLES = 100;

const float exposure = 0.45;
const float decay = 0.98;
const float density = 0.9;
const float weight = 0.07;

in vec2 TexCoords;
in vec3 vPos;

layout (location = 0) out vec4 FragColor;

void main() {   
    vec2 textureCoords = TexCoords;
    vec2 deltaTexCoords = vec2(textureCoords.xy - lightPositionOnScreen.xy);
    deltaTexCoords *= 1.0 /  float(NUM_SAMPLES) * density;
    float illuminationDecay = 1.0;

    // Evaluate summation from Equation 3 ( see https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch13.html) NUM_SAMPLES iterations.
    for(int i = 0; i < NUM_SAMPLES; ++i) {
            textureCoords.x = clamp(textureCoords.x, 0.0, 1.0);
            textureCoords.y = clamp(textureCoords.y, 0.0, 1.0);

            textureCoords -= deltaTexCoords;
            vec4 occlusionSample = texture(occlusionTex, textureCoords);
            float alpha = occlusionSample.r;
            occlusionSample.r = 0.0;
            occlusionSample.a = alpha;

            occlusionSample *= illuminationDecay * weight;

            FragColor += occlusionSample;

            illuminationDecay *= decay;

    FragColor *= exposure;
    float alpha = clamp(1.0 - FragColor.a, 0.0, 1.0);
    FragColor.a = 0.0;
    FragColor.r = alpha;

1 Answer 1


Through trial and error I spotted the issue. I was using the output variable FragColor in my god rays shader to perform the calculations. As a result, OpenGL probably would think a fragment was finished being written to on its first assignment, while it was in fact in the process of a calculation in the loop.

Changing FragColor += occlusionSample; into color += occlusionSample;, where color is a vec4 defined in the scope of the main() and then setting FragColor = color at the end of the calculations solved the issue.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .