> 1; layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = 1) in; layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_gbufferRt0; layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_gbufferRt1; layout(ANKI_TEX_BINDING(0, 2)) uniform sampler2D u_gbufferRt2; layout(ANKI_TEX_BINDING(0, 3)) uniform sampler2D u_depthRt; layout(ANKI_TEX_BINDING(0, 4)) uniform sampler2D u_hizRt; layout(ANKI_TEX_BINDING(0, 5)) uniform sampler2D u_lightBufferRt; layout(ANKI_IMAGE_BINDING(0, 0)) writeonly uniform image2D out_reflAndIndirect; layout(ANKI_SS_BINDING(0, 2)) buffer b_ { vec4 u_irradianceSh[]; }; // Temp buffer to hold the indirect color shared vec3 s_pixels[WORKGROUP_SIZE.y][WORKGROUP_SIZE.x]; #define u_normalMat mat3(u_viewMat) vec4 returnSslrColor(vec3 raySample, float factor, float roughness) { // Re-project previous frame vec4 v4 = u_prevViewProjMatMulInvViewProjMat * vec4(UV_TO_NDC(raySample.xy), raySample.z, 1.0); raySample.xy = NDC_TO_UV(v4.xy / v4.w); raySample.xy = saturate(raySample.xy); vec2 ndc = abs(UV_TO_NDC(raySample.xy)); float contribution = max(ndc.x, ndc.y); contribution = 1.0 - contribution * contribution; contribution *= factor; float lod = float(LIGHT_BUFFER_MIP_COUNT - 1u) * roughness; vec3 color = textureLod(u_lightBufferRt, raySample.xy, lod).rgb; return vec4(color, contribution); } // Note: All calculations in view space vec4 doSslr(vec3 r, vec3 n, vec3 viewPos, vec2 uv, float depth, float roughness) { vec3 p0 = viewPos; // Check for view facing reflections [sakibsaikia] vec3 viewDir = normalize(viewPos); float cameraFacingReflectionAttenuation = 1.0 - smoothstep(0.25, 0.5, dot(-viewDir, r)); if(cameraFacingReflectionAttenuation <= 0.0) { return vec4(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. vec3 p1 = p0 + r * (-p0.z - (u_near + 0.1)); // Start point vec3 start = vec3(uv, depth); // Project end point 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; vec2 texelDims = abs(ray.xy) * vec2(HIZ_SIZE); float stepSize = length(ray.xy) / max(texelDims.x, texelDims.y); ray = normalize(ray); // Compute step const uint BIG_STEP_SKIP = 32u; uint stepSkip = BIG_STEP_SKIP; uint l = gl_GlobalInvocationID.x & 1u; uint j = gl_GlobalInvocationID.y & 1u; const uint STEPS_ARR[4] = uint[](6u, 25u, 13u, 18u); uint step = STEPS_ARR[l * 2u + j]; // Iterate bool found = false; vec3 raySample; ANKI_LOOP for(uint iterations = 0u; iterations < MAX_STEPS; ++iterations) { raySample = start + ray * (float(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; } float depth = textureLod(u_hizRt, raySample.xy, 0.0).r; bool hit = raySample.z - depth >= 0.0; if(!hit) { step += stepSkip; } else if(stepSkip > 1) { step -= BIG_STEP_SKIP - 1u; stepSkip = 1u; } else { found = true; break; } } //return vec4(heatmap(float(iterations) / float(MAX_STEPS)), 1.0); if(found) { return returnSslrColor(raySample, cameraFacingReflectionAttenuation, roughness); } else { return vec4(0.0); } } // Note: All calculations in world space void readReflectionsAndIrradianceFromProbes( uint idxOffset, vec3 worldPos, vec3 normal, float roughness, out vec3 specIndirect, out vec3 diffIndirect) { specIndirect = vec3(0.0); diffIndirect = vec3(0.0); vec3 viewDir = normalize(worldPos - u_cameraPos); vec3 reflDir = reflect(viewDir, normal); float reflLod = float(IR_MIPMAP_COUNT - 1u) * roughness; // Check proxy uint count = u_lightIndices[idxOffset++]; ANKI_LOOP while(count-- != 0) { uint probeIdx = u_lightIndices[idxOffset++]; ReflectionProbe probe = u_reflectionProbes[probeIdx]; float R2 = probe.positionRadiusSq.w; vec3 center = probe.positionRadiusSq.xyz; // Get distance from the center of the probe vec3 f = worldPos - center; // Cubemap UV in view space vec3 uv = computeCubemapVecAccurate(reflDir, R2, f); // Read! float cubemapIndex = probe.cubemapIndexPad3.x; vec3 c = textureLod(u_reflectionsTex, vec4(uv, cubemapIndex), reflLod).rgb; // Combine (lerp) with previous color float d = dot(f, f); float factor = d / R2; factor = min(factor, 1.0); specIndirect = mix(c, specIndirect, factor); // Do the same for diffuse if(gl_GlobalInvocationID.x > 2560. / 2. / 2.) { uv = computeCubemapVecAccurate(normal, R2, f); vec3 id = textureLod(u_irradianceTex, vec4(uv, cubemapIndex), 0.0).rgb; diffIndirect = mix(id, diffIndirect, factor); } else { vec3 nn = normal.yzx; vec3 id; for(uint i = 0u; i < 3u; ++i) { vec4 sh = u_irradianceSh[uint(cubemapIndex) * 3u + i]; id[i] = dot(sh, vec4(1.0, nn)); //id[i] = sh[i]; } diffIndirect = mix(id, diffIndirect, factor); } } } void main() { // Compute a global invocation ID that takes the checkerboard pattern into account ivec2 fixedInvocationId = ivec2(gl_GlobalInvocationID.xy); fixedInvocationId.x *= 2; #if VARIANT == 0 fixedInvocationId.x += ((fixedInvocationId.y + 1) & 1); #else fixedInvocationId.x += ((fixedInvocationId.y + 0) & 1); #endif if(fixedInvocationId.x >= int(FB_SIZE.x) || fixedInvocationId.y >= int(FB_SIZE.y)) { // Skip threads outside the writable image return; } vec2 uv = (vec2(fixedInvocationId) + 0.5) / vec2(FB_SIZE); vec2 ndc = UV_TO_NDC(uv); // Read gbuffer GbufferInfo gbuffer; readGBuffer(u_gbufferRt0, u_gbufferRt1, u_gbufferRt2, uv, 0.0, gbuffer); // Get depth float depth = textureLod(u_depthRt, uv, 0.0).r; // Get world position vec4 worldPos4 = u_invViewProjMat * vec4(ndc, depth, 1.0); vec3 worldPos = worldPos4.xyz / worldPos4.w; // Compute env BRDF vec3 env; { vec3 viewDir = normalize(u_cameraPos - worldPos); float NoV = max(EPSILON, dot(gbuffer.normal, viewDir)); env = envBRDF(gbuffer.specular, gbuffer.roughness, u_integrationLut, NoV); } // Try SSR float sslrFactor = 0.0; vec3 sslrCol = vec3(0.0); if(env.g > 0.05) { // Get view pos vec4 viewPos4 = u_invProjMat * vec4(UV_TO_NDC(uv), depth, 1.0); vec3 viewPos = viewPos4.xyz / viewPos4.w; // Do SSLR vec3 viewDir = normalize(viewPos); vec3 viewNormal = u_normalMat * gbuffer.normal; vec3 reflVec = reflect(viewDir, viewNormal); vec4 sslr = doSslr(reflVec, viewNormal, viewPos, uv, depth, gbuffer.roughness); sslrFactor = sslr.w; sslrCol = sslr.xyz; sslrCol = clamp(sslrCol, 0.0, FLT_MAX); // Fix the value just in case } // Read probes vec3 probeCol = vec3(0.0); vec3 indirectCol = vec3(0.0); { // Get first light index uint clusterIdx = computeClusterIndex(u_clustererMagic, uv, worldPos, CLUSTER_COUNT_X, CLUSTER_COUNT_Y); uint idxOffset = u_clusters[clusterIdx]; // Skip decals uint count = u_lightIndices[idxOffset++]; idxOffset += count; // Skip point lights count = u_lightIndices[idxOffset++]; idxOffset += count; // Skip spot lights count = u_lightIndices[idxOffset++]; idxOffset += count; // Do the probe read readReflectionsAndIrradianceFromProbes( idxOffset, worldPos, gbuffer.normal, gbuffer.roughness, probeCol, indirectCol); } // Combine the SSR and probe reflections and write the result vec3 finalRefl = mix(probeCol, sslrCol, sslrFactor); // Compute the final color vec3 outColor = indirectCol /* gbuffer.diffuse + finalRefl * env*/; // 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 = int(gl_LocalInvocationID.y); storePixel.y = fixedInvocationId.y; #if VARIANT == 0 bool pickRightNeighbour = (fixedInvocationId.y & 1) == 1; #else bool pickRightNeighbour = (fixedInvocationId.y & 1) == 0; #endif int xOffset = (pickRightNeighbour) ? 1 : -1; readPixel.x = int(gl_LocalInvocationID.x) + xOffset; readPixel.x = clamp(readPixel.x, 0, int(WORKGROUP_SIZE.x - 1)); storePixel.x = fixedInvocationId.x + xOffset; vec3 missingColor = (outColor + s_pixels[readPixel.y][readPixel.x]) * 0.5; // average // Store both the pixels imageStore(out_reflAndIndirect, fixedInvocationId, vec4(outColor, 0.0)); imageStore(out_reflAndIndirect, storePixel, vec4(missingColor, 0.0)); } ]]>