| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- // Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #pragma anki mutator RAYS_PER_PIXEL 1 2 4 8
- #pragma anki library RtShadows
- #pragma anki ray_type 0
- #pragma anki start rgen
- #include <AnKi/Shaders/ImportanceSampling.glsl>
- #include <AnKi/Shaders/PackFunctions.glsl>
- #include <AnKi/Shaders/RtShadows.glsl>
- #define CLUSTERED_SHADING_SET 0u
- #define CLUSTERED_SHADING_UNIFORMS_BINDING 0u
- #define CLUSTERED_SHADING_LIGHTS_BINDING 1u
- #define CLUSTERED_SHADING_CLUSTERS_BINDING 4u
- #include <AnKi/Shaders/ClusteredShadingCommon.glsl>
- // Used by the hit shaders. When changing the binding you need to update other shaders
- layout(set = 0, binding = 5) uniform sampler u_trilinearRepeatSampler;
- layout(set = 0, binding = 6) uniform uimage2D u_shadowsImage;
- layout(set = 0, binding = 7) uniform utexture2D u_historyShadowsTex;
- layout(set = 0, binding = 8) uniform sampler u_linearAnyClampSampler;
- layout(set = 0, binding = 9) uniform sampler u_nearestAnyClampSampler;
- layout(set = 0, binding = 10) uniform texture2D u_depthRt;
- layout(set = 0, binding = 11) uniform texture2D u_motionVectorsRt;
- layout(set = 0, binding = 12) uniform texture2D u_historyLengthTex;
- layout(set = 0, binding = 13) uniform texture2D u_normalRt;
- layout(set = 0, binding = 14) uniform accelerationStructureEXT u_tlas;
- layout(set = 0, binding = 15) uniform texture2D u_prevMomentsTex;
- layout(set = 0, binding = 16) uniform image2D u_momentsImage;
- layout(set = 0, binding = 17) uniform texture2D u_blueNoiseTex;
- ANKI_BINDLESS_SET(1); // Used by the hit shaders
- layout(push_constant, std430) uniform b_pc
- {
- RtShadowsUniforms u_unis;
- };
- layout(location = 0) rayPayloadEXT F32 g_payload;
- F32 trace(const Vec3 rayOrigin, const Vec3 rayDir, F32 tMax)
- {
- const U32 flags = gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT;
- const U32 cullMask = 0xFFu;
- const U32 sbtRecordOffset = 0u;
- const U32 sbtRecordStride = 0u;
- const U32 missIndex = 0u;
- const F32 tMin = 0.1;
- const I32 payloadLocation = 0;
- g_payload = 0.0;
- traceRayEXT(u_tlas, flags, cullMask, sbtRecordOffset, sbtRecordStride, missIndex, rayOrigin, tMin, rayDir, tMax,
- payloadLocation);
- return g_payload;
- }
- void main()
- {
- // World position
- const Vec2 uv = (Vec2(gl_LaunchIDEXT.xy) + 0.5) / Vec2(gl_LaunchSizeEXT.xy);
- const Vec2 ndc = UV_TO_NDC(uv);
- const F32 depth = textureLod(u_depthRt, u_linearAnyClampSampler, uv, 0.0).r;
- const Vec4 worldPos4 = u_clusteredShading.m_matrices.m_invertedViewProjectionJitter * Vec4(ndc, depth, 1.0);
- const Vec3 worldPos = worldPos4.xyz / worldPos4.w;
- if(depth == 1.0)
- {
- imageStore(u_shadowsImage, IVec2(gl_LaunchIDEXT.xy), UVec4(0));
- imageStore(u_momentsImage, IVec2(gl_LaunchIDEXT.xy), Vec4(0.0));
- return;
- }
- // World normal
- const Vec3 normal = unpackNormalFromGBuffer(textureLod(u_normalRt, u_linearAnyClampSampler, uv, 0.0));
- // Cluster
- Cluster cluster = getClusterFragCoord(Vec3(uv * u_clusteredShading.m_renderingSize, depth));
- F32 shadowFactors[MAX_RT_SHADOW_LAYERS];
- zeroRtShadowLayers(shadowFactors);
- // Get a random factor
- Vec3 random[RAYS_PER_PIXEL];
- for(I32 i = 0; i < RAYS_PER_PIXEL; ++i)
- {
- const U32 frameIdx = u_clusteredShading.m_frame * U32(RAYS_PER_PIXEL + i);
- #if 0
- const UVec3 irandom = rand3DPCG16(UVec3(gl_LaunchIDEXT.xy, frameIdx));
- random[i] = Vec3(irandom) / F32(0xFFFF) * 2.0 - 1.0; // In [-1.0, 1.0]
- #else
- random[i] =
- textureLod(u_blueNoiseTex, u_trilinearRepeatSampler, Vec2(gl_LaunchSizeEXT.xy) / Vec2(64.0) * uv, 0.0).rgb;
- random[i] = animateBlueNoise(random[i], frameIdx);
- random[i] = random[i] * 2.0 - 1.0; // In [-1.0, 1.0]
- #endif
- }
- // Dir light
- const DirectionalLight dirLight = u_clusteredShading.m_directionalLight;
- ANKI_BRANCH if(dirLight.m_active != 0u && dirLight.m_cascadeCount > 0u)
- {
- for(I32 i = 0; i < RAYS_PER_PIXEL; ++i)
- {
- const Vec3 dirLightPos = worldPos + -dirLight.m_direction * 10.0 + random[i];
- const Vec3 rayDir = normalize(dirLightPos - worldPos);
- const F32 lambertTerm = dot(rayDir, normal);
- ANKI_BRANCH if(lambertTerm > 0.0)
- {
- shadowFactors[dirLight.m_shadowLayer] += trace(worldPos, rayDir, 10000.0) / F32(RAYS_PER_PIXEL);
- }
- }
- }
- // Point lights
- ANKI_LOOP while(cluster.m_pointLightsMask != ExtendedClusterObjectMask(0))
- {
- const I32 idx = findLSB2(cluster.m_pointLightsMask);
- cluster.m_pointLightsMask &= ~(ExtendedClusterObjectMask(1) << ExtendedClusterObjectMask(idx));
- const PointLight light = u_pointLights2[idx];
- ANKI_BRANCH if(light.m_shadowAtlasTileScale >= 0.0)
- {
- for(I32 i = 0; i < RAYS_PER_PIXEL; ++i)
- {
- const Vec3 lightPos = light.m_position + 0.05 * light.m_radius * random[i];
- const Vec3 toLight = lightPos - worldPos;
- const F32 distanceToLight = length(toLight);
- const Vec3 rayDir = toLight / distanceToLight; // normalize
- const Bool inside = distanceToLight < light.m_radius;
- const F32 lambertTerm = dot(rayDir, normal);
- ANKI_BRANCH if(inside && lambertTerm > 0.0)
- {
- shadowFactors[light.m_shadowLayer] +=
- trace(worldPos, rayDir, distanceToLight) / F32(RAYS_PER_PIXEL);
- }
- }
- }
- }
- // Spot lights
- ANKI_LOOP while(cluster.m_spotLightsMask != ExtendedClusterObjectMask(0))
- {
- const I32 idx = findLSB2(cluster.m_spotLightsMask);
- cluster.m_spotLightsMask &= ~(ExtendedClusterObjectMask(1) << ExtendedClusterObjectMask(idx));
- const SpotLight light = u_spotLights[idx];
- ANKI_BRANCH if(light.m_shadowLayer != MAX_U32)
- {
- for(I32 i = 0; i < RAYS_PER_PIXEL; ++i)
- {
- const Vec3 lightPos = light.m_position + 0.05 * light.m_radius * random[i];
- const Vec3 toLight = lightPos - worldPos;
- const F32 distanceToLight = length(toLight);
- const Vec3 rayDir = toLight / distanceToLight; // normalize
- const F32 lambertTerm = dot(rayDir, normal);
- ANKI_BRANCH if(lambertTerm > 0.0)
- {
- shadowFactors[light.m_shadowLayer] +=
- trace(worldPos, rayDir, distanceToLight) / F32(RAYS_PER_PIXEL);
- }
- }
- }
- }
- // Get history length
- const Vec2 historyUv = uv + textureLod(u_motionVectorsRt, u_linearAnyClampSampler, uv, 0.0).xy;
- const F32 historyLength = textureLod(u_historyLengthTex, u_linearAnyClampSampler, uv, 0.0).x;
- // Compute blend fractor. Use nearest sampler because it's an integer texture
- const F32 lowestBlendFactor = 0.1;
- const F32 stableFrames = 4.0;
- const F32 lerp = min(1.0, (historyLength * RT_SHADOWS_MAX_HISTORY_LENGTH - 1.0) / stableFrames);
- const F32 blendFactor = mix(1.0, lowestBlendFactor, lerp);
- // Blend with history
- const UVec4 packedhistory = textureLod(u_historyShadowsTex, u_nearestAnyClampSampler, historyUv, 0.0);
- F32 history[MAX_RT_SHADOW_LAYERS];
- unpackRtShadows(packedhistory, history);
- for(U32 i = 0u; i < MAX_RT_SHADOW_LAYERS; ++i)
- {
- const F32 lerp = min(1.0, u_unis.historyRejectFactor[i] + blendFactor);
- shadowFactors[i] = mix(history[i], shadowFactors[i], lerp);
- }
- // Store the shadows image
- const UVec4 packed = packRtShadows(shadowFactors);
- imageStore(u_shadowsImage, IVec2(gl_LaunchIDEXT.xy), packed);
- // Compute the moments that will give temporal variance
- Vec2 moments = Vec2(0.0);
- ANKI_UNROLL for(U32 i = 0u; i < MAX_RT_SHADOW_LAYERS; ++i)
- {
- moments.x += shadowFactors[i];
- }
- moments.y = moments.x * moments.x;
- // Blend the moments
- const Vec2 prevMoments = textureLod(u_prevMomentsTex, u_linearAnyClampSampler, historyUv, 0.0).xy;
- const F32 lowestMomentsBlendFactor = 0.2;
- const F32 momentsBlendFactor = mix(1.0, lowestMomentsBlendFactor, lerp);
- moments = mix(prevMoments, moments, momentsBlendFactor);
- // Store the moments
- imageStore(u_momentsImage, IVec2(gl_LaunchIDEXT.xy), Vec4(moments, 0.0, 0.0));
- }
- #pragma anki end
|