Last active
February 4, 2021 02:39
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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