|
|
@@ -11,132 +11,29 @@
|
|
|
|
|
|
#pragma anki mutator VARIANT 0 1
|
|
|
|
|
|
-ANKI_SPECIALIZATION_CONSTANT_UVEC2(FB_SIZE, 0, UVec2(1));
|
|
|
-ANKI_SPECIALIZATION_CONSTANT_U32(MAX_STEPS, 2, 1);
|
|
|
-ANKI_SPECIALIZATION_CONSTANT_U32(LIGHT_BUFFER_MIP_COUNT, 3, 1);
|
|
|
-ANKI_SPECIALIZATION_CONSTANT_F32(HISTORY_COLOR_BLEND_FACTOR, 4, 0.5);
|
|
|
-
|
|
|
#pragma anki start comp
|
|
|
#include <shaders/Functions.glsl>
|
|
|
#include <shaders/Pack.glsl>
|
|
|
#include <shaders/glsl_cpp_common/Ssr.h>
|
|
|
#include <shaders/Tonemapping.glsl>
|
|
|
+#include <shaders/SsRaymarching.glsl>
|
|
|
|
|
|
const UVec2 WORKGROUP_SIZE = UVec2(16, 16);
|
|
|
layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in;
|
|
|
|
|
|
layout(set = 0, binding = 0) uniform sampler u_trilinearClampSampler;
|
|
|
-layout(set = 0, binding = 1) uniform texture2D u_gbufferRt1;
|
|
|
-layout(set = 0, binding = 2) uniform texture2D u_gbufferRt2;
|
|
|
-layout(set = 0, binding = 3) uniform texture2D u_depthRt;
|
|
|
-layout(set = 0, binding = 4) uniform texture2D u_lightBufferRt;
|
|
|
+layout(set = 0, binding = 1) uniform sampler u_nearestNearestClampSampler;
|
|
|
+layout(set = 0, binding = 2) uniform texture2D u_gbufferRt1;
|
|
|
+layout(set = 0, binding = 3) uniform texture2D u_gbufferRt2;
|
|
|
+layout(set = 0, binding = 4) uniform texture2D u_depthRt;
|
|
|
+layout(set = 0, binding = 5) uniform texture2D u_lightBufferRt;
|
|
|
|
|
|
-layout(set = 0, binding = 5, rgba16f) uniform image2D out_img;
|
|
|
+layout(set = 0, binding = 6, rgba16f) uniform image2D out_img;
|
|
|
|
|
|
-layout(set = 0, binding = 6, row_major) uniform u_
|
|
|
+layout(set = 0, binding = 7, row_major) uniform u_
|
|
|
{
|
|
|
SsrUniforms u_unis;
|
|
|
};
|
|
|
-#define u_prevViewProjMatMulInvViewProjMat u_unis.m_prevViewProjMatMulInvViewProjMat
|
|
|
-#define u_near u_unis.m_nearPad3.x
|
|
|
-#define u_projMat u_unis.m_projMat
|
|
|
-#define u_invProjMat u_unis.m_invProjMat
|
|
|
-#define u_normalMat u_unis.m_normalMat
|
|
|
-
|
|
|
-// Temp buffer to hold the indirect color
|
|
|
-shared Vec4 s_pixels[WORKGROUP_SIZE.y][WORKGROUP_SIZE.x];
|
|
|
-
|
|
|
-// Note: All calculations in view space
|
|
|
-// It returns the UV coordinates of the reflection (xy) and the contrubution factor (z)
|
|
|
-Vec3 raymarch(Vec3 r, Vec3 n, Vec3 viewPos, Vec2 uv, F32 depth)
|
|
|
-{
|
|
|
- const Vec3 p0 = viewPos;
|
|
|
-
|
|
|
- // Check for view facing reflections [sakibsaikia]
|
|
|
- const Vec3 viewDir = normalize(viewPos);
|
|
|
- const F32 cameraContribution = 1.0 - smoothstep(0.25, 0.5, dot(-viewDir, r));
|
|
|
- if(cameraContribution <= 0.0)
|
|
|
- {
|
|
|
- return Vec3(0.0);
|
|
|
- }
|
|
|
-
|
|
|
- // Compute an end point p1. This point is supposed to fall in front of the near plane. Add a small padding to near
|
|
|
- // to avoid having p1 touching the near plane.
|
|
|
- const F32 p0DistFromNear = -p0.z - (u_near + 0.1); // aka testPlane(near, p0)
|
|
|
- const Vec3 p1 = p0 + r * p0DistFromNear; // Whatever the direction of r, p1 won't touch the near plane
|
|
|
-
|
|
|
- // Start point
|
|
|
- const Vec3 start = Vec3(uv, depth);
|
|
|
-
|
|
|
- // Project end point
|
|
|
- const Vec4 end4 = u_projMat * Vec4(p1, 1.0);
|
|
|
- Vec3 end = end4.xyz / end4.w;
|
|
|
- end.xy = NDC_TO_UV(end.xy);
|
|
|
-
|
|
|
- // Compute the ray and step size
|
|
|
- Vec3 ray = end - start;
|
|
|
- const Vec2 texelDims = abs(ray.xy) * Vec2(FB_SIZE);
|
|
|
- const F32 stepSize = length(ray.xy) / max(texelDims.x, texelDims.y);
|
|
|
- ray = normalize(ray);
|
|
|
-
|
|
|
- // Compute step
|
|
|
- const U32 BIG_STEP_SKIP = 16u;
|
|
|
- U32 stepSkip = BIG_STEP_SKIP;
|
|
|
-
|
|
|
- const U32 STEP_FRACTION = BIG_STEP_SKIP / (4u + 1u);
|
|
|
- const U32 STEPS_ARR[4] = U32[](STEP_FRACTION, 4 * STEP_FRACTION, 2 * STEP_FRACTION, 3 * STEP_FRACTION);
|
|
|
- const U32 l = gl_GlobalInvocationID.x & 1u;
|
|
|
- const U32 j = gl_GlobalInvocationID.y & 1u;
|
|
|
- U32 step = STEPS_ARR[l * 2u + j];
|
|
|
-
|
|
|
- // Iterate
|
|
|
- F32 finalContribution = 0.0;
|
|
|
- Vec3 raySample;
|
|
|
- ANKI_LOOP for(U32 iterations = 0u; iterations < MAX_STEPS; ++iterations)
|
|
|
- {
|
|
|
- raySample = start + ray * (F32(step) * stepSize);
|
|
|
-
|
|
|
- // Check if it's out of the view
|
|
|
- if(raySample.x <= 0.0 || raySample.y <= 0.0 || raySample.x >= 1.0 || raySample.y >= 1.0)
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- const F32 depth = textureLod(u_depthRt, u_trilinearClampSampler, raySample.xy, 0.0).r;
|
|
|
-
|
|
|
- const Bool hit = raySample.z - depth >= 0.0;
|
|
|
- if(!hit)
|
|
|
- {
|
|
|
- step += stepSkip;
|
|
|
- }
|
|
|
- else if(stepSkip > 1)
|
|
|
- {
|
|
|
- step -= BIG_STEP_SKIP - 1u;
|
|
|
- stepSkip = 1u;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // Found it
|
|
|
-
|
|
|
- // Re-project previous frame
|
|
|
- const Vec4 v4 = u_prevViewProjMatMulInvViewProjMat * Vec4(UV_TO_NDC(raySample.xy), raySample.z, 1.0);
|
|
|
- Vec2 ndc = v4.xy / v4.w;
|
|
|
- raySample.xy = NDC_TO_UV(ndc);
|
|
|
-
|
|
|
- // Compute the edge contribution
|
|
|
- ndc = abs(ndc);
|
|
|
- F32 screedEdgeContributionFactor = max(ndc.x, ndc.y);
|
|
|
- screedEdgeContributionFactor = 1.0 - screedEdgeContributionFactor * screedEdgeContributionFactor;
|
|
|
- screedEdgeContributionFactor = saturate(screedEdgeContributionFactor);
|
|
|
- finalContribution = cameraContribution * screedEdgeContributionFactor;
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Return the traced UV and the contribution factor
|
|
|
- return Vec3(raySample.xy, finalContribution);
|
|
|
-}
|
|
|
|
|
|
void main()
|
|
|
{
|
|
|
@@ -149,13 +46,13 @@ void main()
|
|
|
fixedInvocationId.x += ((fixedInvocationId.y + 0) & 1);
|
|
|
#endif
|
|
|
|
|
|
- if(fixedInvocationId.x >= I32(FB_SIZE.x) || fixedInvocationId.y >= I32(FB_SIZE.y))
|
|
|
+ if(fixedInvocationId.x >= I32(u_unis.m_framebufferSize.x) || fixedInvocationId.y >= I32(u_unis.m_framebufferSize.y))
|
|
|
{
|
|
|
// Skip threads outside the writable image
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- const Vec2 uv = (Vec2(fixedInvocationId.xy) + 0.5) / Vec2(FB_SIZE);
|
|
|
+ const Vec2 uv = (Vec2(fixedInvocationId.xy) + 0.5) / Vec2(u_unis.m_framebufferSize);
|
|
|
|
|
|
// Read part of the G-buffer
|
|
|
const F32 roughness = readRoughnessFromGBuffer(u_gbufferRt1, u_trilinearClampSampler, uv);
|
|
|
@@ -165,75 +62,62 @@ void main()
|
|
|
const F32 depth = textureLod(u_depthRt, u_trilinearClampSampler, uv, 0.0).r;
|
|
|
|
|
|
// Get view pos
|
|
|
- const Vec4 viewPos4 = u_invProjMat * Vec4(UV_TO_NDC(uv), depth, 1.0);
|
|
|
+ const Vec4 viewPos4 = u_unis.m_invProjMat * Vec4(UV_TO_NDC(uv), depth, 1.0);
|
|
|
const Vec3 viewPos = viewPos4.xyz / viewPos4.w;
|
|
|
|
|
|
// Compute refl vector
|
|
|
const Vec3 viewDir = normalize(viewPos);
|
|
|
- const Vec3 viewNormal = u_normalMat * worldNormal;
|
|
|
+ const Vec3 viewNormal = u_unis.m_normalMat * worldNormal;
|
|
|
const Vec3 reflVec = reflect(viewDir, viewNormal);
|
|
|
|
|
|
- // Raymatch
|
|
|
- const Vec3 ssr = raymarch(reflVec, viewNormal, viewPos, uv, depth);
|
|
|
- const Vec2 reflUv = ssr.xy;
|
|
|
- const F32 factor = ssr.z;
|
|
|
+ // Rand idx
|
|
|
+ U32 randIdx = (fixedInvocationId.x & 1) * 2 + (fixedInvocationId.y & 1);
|
|
|
+ randIdx = (randIdx + u_unis.m_frameCount & 3) & 3;
|
|
|
+
|
|
|
+ // Do the heavy work
|
|
|
+ Vec3 hitPoint;
|
|
|
+ F32 hitAttenuation;
|
|
|
+ const U32 lod = 1;
|
|
|
+ raymarchGroundTruth(viewPos,
|
|
|
+ reflVec,
|
|
|
+ uv,
|
|
|
+ depth,
|
|
|
+ u_unis.m_projMat,
|
|
|
+ randIdx,
|
|
|
+ u_unis.m_maxSteps,
|
|
|
+ u_depthRt,
|
|
|
+ u_nearestNearestClampSampler,
|
|
|
+ F32(lod),
|
|
|
+ u_unis.m_depthBufferSize >> lod,
|
|
|
+ 16u,
|
|
|
+ hitPoint,
|
|
|
+ hitAttenuation);
|
|
|
|
|
|
// Read the reflection
|
|
|
Vec4 outColor;
|
|
|
- ANKI_BRANCH if(factor > 0.0)
|
|
|
+ ANKI_BRANCH if(hitAttenuation > 0.0)
|
|
|
{
|
|
|
// Read the refl
|
|
|
- const F32 lod = F32(LIGHT_BUFFER_MIP_COUNT - 1u) * roughness;
|
|
|
- outColor.rgb = textureLod(u_lightBufferRt, u_trilinearClampSampler, reflUv, lod).rgb;
|
|
|
+
|
|
|
+ // Reproject the UV because you are reading the previous frame
|
|
|
+ const Vec4 v4 = u_unis.m_prevViewProjMatMulInvViewProjMat * Vec4(UV_TO_NDC(hitPoint.xy), hitPoint.z, 1.0);
|
|
|
+ hitPoint.xy = NDC_TO_UV(v4.xy / v4.w);
|
|
|
+
|
|
|
+ // Compute the LOD based on the roughness
|
|
|
+ const F32 lod = F32(u_unis.m_lightBufferMipCount - 1u) * roughness;
|
|
|
+
|
|
|
+ // Read the light buffer
|
|
|
+ outColor.rgb = textureLod(u_lightBufferRt, u_trilinearClampSampler, hitPoint.xy, lod).rgb;
|
|
|
outColor.rgb = clamp(outColor.rgb, 0.0, FLT_MAX); // Fix the value just in case
|
|
|
- outColor.rgb *= factor;
|
|
|
- outColor.a = 1.0 - factor;
|
|
|
+ outColor.rgb *= hitAttenuation;
|
|
|
+ outColor.a = 1.0 - hitAttenuation;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
outColor = Vec4(0.0, 0.0, 0.0, 1.0);
|
|
|
}
|
|
|
|
|
|
- // Use the prev color
|
|
|
- if(HISTORY_COLOR_BLEND_FACTOR > 0.0)
|
|
|
- {
|
|
|
- const Vec4 v4 = u_prevViewProjMatMulInvViewProjMat * Vec4(UV_TO_NDC(uv), depth, 1.0);
|
|
|
- const Vec2 oldNdc = v4.xy / v4.w;
|
|
|
- const Vec2 oldUv = saturate(NDC_TO_UV(oldNdc));
|
|
|
-
|
|
|
- const Vec4 prevColor = imageLoad(out_img, ivec2(oldUv * vec2(FB_SIZE)));
|
|
|
-
|
|
|
- outColor = mix(prevColor, outColor, HISTORY_COLOR_BLEND_FACTOR);
|
|
|
- }
|
|
|
-
|
|
|
- // Store the color for the resolve
|
|
|
- s_pixels[gl_LocalInvocationID.y][gl_LocalInvocationID.x] = outColor;
|
|
|
-
|
|
|
- // Wait for all the threads to store their stuff
|
|
|
- memoryBarrierShared();
|
|
|
- barrier();
|
|
|
-
|
|
|
- // Compute the missing pixel by resolving with the right or left neighbour
|
|
|
- IVec2 readPixel, storePixel;
|
|
|
- readPixel.y = I32(gl_LocalInvocationID.y);
|
|
|
- storePixel.y = fixedInvocationId.y;
|
|
|
-
|
|
|
-#if VARIANT == 0
|
|
|
- const Bool pickRightNeighbour = (fixedInvocationId.y & 1) == 1;
|
|
|
-#else
|
|
|
- const Bool pickRightNeighbour = (fixedInvocationId.y & 1) == 0;
|
|
|
-#endif
|
|
|
- const I32 xOffset = (pickRightNeighbour) ? 1 : -1;
|
|
|
-
|
|
|
- readPixel.x = I32(gl_LocalInvocationID.x) + xOffset;
|
|
|
- readPixel.x = clamp(readPixel.x, 0, I32(WORKGROUP_SIZE.x - 1));
|
|
|
-
|
|
|
- storePixel.x = fixedInvocationId.x + xOffset;
|
|
|
-
|
|
|
- const Vec4 missingColor = (outColor + s_pixels[readPixel.y][readPixel.x]) * 0.5; // average
|
|
|
-
|
|
|
- // Store both the pixels
|
|
|
+ // Store
|
|
|
imageStore(out_img, fixedInvocationId, outColor);
|
|
|
- imageStore(out_img, storePixel, missingColor);
|
|
|
}
|
|
|
#pragma anki end
|