Skip to content

Instantly share code, notes, and snippets.

@JuanDiegoMontoya
Last active February 4, 2021 02:39
Show Gist options
  • Save JuanDiegoMontoya/2d5096847faf5e865bbf3372300757b1 to your computer and use it in GitHub Desktop.
Save JuanDiegoMontoya/2d5096847faf5e865bbf3372300757b1 to your computer and use it in GitHub Desktop.
Fragment shader which, given a shadow map, will generate volumetric light shafts in a scene. No optimizations included.
#version 460 core
layout (location = 0) in vec2 vTexCoord; // could be calculated in FS with screen-space coords
layout (location = 0) uniform sampler2D u_hdrBuffer; // final HDR scene image (before tonemapping)
layout (location = 1) uniform sampler2D gDepth; // scene depth buffer from eye PoV
layout (location = 2) uniform sampler2D shadowDepth;
layout (location = 3) uniform mat4 u_invViewProj;
layout (location = 4) uniform mat4 u_lightMatrix;
layout (location = 0) out vec4 fragColor;
vec3 WorldPosFromDepth(float depth, vec2 screenSize, mat4 invViewProj)
{
float z = depth * 2.0 - 1.0;
vec2 normalized = gl_FragCoord.xy / screenSize;
vec4 clipSpacePosition = vec4(normalized * 2.0 - 1.0, z, 1.0);
// undo view + projection
vec4 worldSpacePosition = invViewProj * clipSpacePosition;
worldSpacePosition /= worldSpacePosition.w;
return worldSpacePosition.xyz;
}
float Shadow(vec4 lightSpacePos)
{
vec3 projCoords = lightSpacePos.xyz / lightSpacePos.w;
if(projCoords.z > 1.0) return 0.0;
projCoords = projCoords * 0.5 + 0.5;
float closestDepth = texture(shadowDepth, projCoords.xy).r;
float currentDepth = projCoords.z;
float shadow = currentDepth > closestDepth ? 1.0 : 0.0;
return shadow;
}
// these should be uniforms, oh well
const int NUM_STEPS = 50;
const float intensity = .02;
const float distToFullIntensity = 20.0;
void main()
{
const vec3 rayEnd = WorldPosFromDepth(texture(gDepth, vTexCoord).r, textureSize(gDepth, 0), u_invViewProj);
const vec3 rayStart = WorldPosFromDepth(0, textureSize(gDepth, 0), u_invViewProj);
const vec3 rayDir = normalize(rayEnd - rayStart);
const float dist = distance(rayEnd, rayStart);
const float rayStep = dist / NUM_STEPS;
vec3 rayPos = rayStart;
float accum = 0.0;
for (int i = 0; i < NUM_STEPS; i++)
{
vec4 lightSpacePos = u_lightMatrix * vec4(rayPos, 1.0);
accum += 1.0 - Shadow(lightSpacePos);
rayPos += rayDir * rayStep;
}
// output can be whatever, here we are compositing volumetrics with final scene image
fragColor = vec4((dist / distToFullIntensity) * intensity * (accum / NUM_STEPS) + texture(u_hdrBuffer, vTexCoord).rgb, 1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment