Browse Source

Small reflection refactoring

Panagiotis Christopoulos Charitos 11 months ago
parent
commit
c0d5cc6eca
2 changed files with 140 additions and 102 deletions
  1. 62 69
      AnKi/Shaders/Reflections.ankiprog
  2. 78 33
      AnKi/Shaders/SsRaymarching.hlsl

+ 62 - 69
AnKi/Shaders/Reflections.ankiprog

@@ -206,8 +206,6 @@ groupshared U32 g_allSky;
 // SSR                                                                       =
 // SSR                                                                       =
 // ===========================================================================
 // ===========================================================================
 #if NOT_ZERO(ANKI_TECHNIQUE_Ssr)
 #if NOT_ZERO(ANKI_TECHNIQUE_Ssr)
-constexpr F32 kLowAttenuation = 0.01;
-
 SamplerState g_trilinearClampSampler : register(s0);
 SamplerState g_trilinearClampSampler : register(s0);
 SamplerComparisonState g_shadowSampler : register(s1);
 SamplerComparisonState g_shadowSampler : register(s1);
 
 
@@ -233,7 +231,7 @@ ANKI_FAST_CONSTANTS(ReflectionConstants, g_consts)
 
 
 #	define NUM_THREADS_SQRT 8
 #	define NUM_THREADS_SQRT 8
 
 
-groupshared Vec4 g_viewHitPointAndAttenuation[NUM_THREADS_SQRT][NUM_THREADS_SQRT];
+groupshared Vec4 g_viewHitPointAndSsrSuccess[NUM_THREADS_SQRT][NUM_THREADS_SQRT];
 groupshared Vec4 g_colorAndDepth[NUM_THREADS_SQRT][NUM_THREADS_SQRT];
 groupshared Vec4 g_colorAndDepth[NUM_THREADS_SQRT][NUM_THREADS_SQRT];
 
 
 Vec3 doLightShading(Vec3 worldPos, Vec3 viewPos, UVec2 coord, F32 depth)
 Vec3 doLightShading(Vec3 worldPos, Vec3 viewPos, UVec2 coord, F32 depth)
@@ -276,81 +274,76 @@ Vec3 doLightShading(Vec3 worldPos, Vec3 viewPos, UVec2 coord, F32 depth)
 	return outColor;
 	return outColor;
 }
 }
 
 
-void doSsr(UVec2 logicalViewportSize, UVec2 realCoord, UVec2 logicalCoord, Vec2 uv, Vec3 viewPos, F32 depth, F32 randFactor, F32 roughness,
-		   inout Vec3 viewReflDir, out F32 attenuation, out Vec3 outColor, out Vec3 viewHitPoint)
+struct SampleNormalFunc
+{
+	Vec3 sample(Vec2 uv)
+	{
+		const Vec3 gbufferNormal = unpackNormalFromGBuffer(g_gbufferRt2.SampleLevel(g_trilinearClampSampler, uv, 0.0));
+		const Vec3 newNormal = mul(g_globalRendererConstants.m_matrices.m_view, Vec4(gbufferNormal, 0.0));
+		return newNormal;
+	}
+};
+
+// Calculations in view space
+Bool doSsr(UVec2 logicalViewportSize, UVec2 realCoord, UVec2 logicalCoord, Vec2 uv, Vec3 viewPos, F32 depth, F32 randFactor, F32 roughness,
+		   Vec3 viewReflDir, out Vec3 outColor, out Vec3 viewHitPoint)
 {
 {
-	attenuation = 0.0;
 	outColor = 0.0;
 	outColor = 0.0;
 	viewHitPoint = 0.0;
 	viewHitPoint = 0.0;
 
 
 	// Trace
 	// Trace
-	Vec3 hitPoint;
+	Vec2 hitUv;
+	F32 hitDepth;
 	{
 	{
-		const U32 lod = 8u; // Use the max LOD for ray marching
-		const U32 stepIncrement = g_consts.m_ssrStepIncrement;
-		const F32 stepIncrementf = F32(stepIncrement);
-		const F32 minStepf = min(4.0f, stepIncrementf);
-		const U32 initialStepIncrement = U32(lerp(minStepf, stepIncrementf, randFactor));
-		raymarchGroundTruth(viewPos, viewReflDir, uv, depth, g_globalRendererConstants.m_matrices.m_projMat00_11_22_23, g_consts.m_ssrMaxIterations,
-							g_downscaledDepthTex, g_trilinearClampSampler, F32(lod), stepIncrement, initialStepIncrement, hitPoint, attenuation);
-	}
+		RayMarchingConfig config = (RayMarchingConfig)0;
+		config.m_maxIterations = g_consts.m_ssrStepIncrement;
+		config.m_depthTextureLod = 8.0; // Use the max LOD for ray marching
+		config.m_stepIncrement = g_consts.m_ssrStepIncrement;
 
 
-	if(attenuation < kLowAttenuation)
-	{
-		viewHitPoint = cheapPerspectiveUnprojection(g_globalRendererConstants.m_matrices.m_unprojectionParameters, uvToNdc(hitPoint.xy), hitPoint.z);
-		return;
-	}
+		const F32 minStepf = min(4u, config.m_stepIncrement);
+		config.m_initialStepIncrement = U32(lerp(minStepf, config.m_stepIncrement, randFactor));
 
 
-	const F32 depth1 = g_downscaledDepthTex.SampleLevel(g_trilinearClampSampler, hitPoint.xy, 0.0).r;
-	viewHitPoint = cheapPerspectiveUnprojection(g_globalRendererConstants.m_matrices.m_unprojectionParameters, uvToNdc(hitPoint.xy), depth1);
-
-	// Reject backfacing
-	if(kExtraSsrRejection)
-	{
-		const Vec3 gbufferNormal = unpackNormalFromGBuffer(g_gbufferRt2.SampleLevel(g_trilinearClampSampler, hitPoint.xy, 0.0));
-		const Vec3 hitNormal = mul(g_globalRendererConstants.m_matrices.m_view, Vec4(gbufferNormal, 0.0));
-		F32 backFaceAttenuation;
-		rejectBackFaces(viewReflDir, hitNormal, backFaceAttenuation);
-		attenuation *= backFaceAttenuation;
-		if(attenuation < kLowAttenuation)
+		if(kExtraSsrRejection)
 		{
 		{
-			return;
+			config.m_backfaceRejection = true;
+			config.m_minRayToBackgroundDistance = lerp(0.1f, 0.6f, roughness);
+		}
+		else
+		{
+			config.m_backfaceRejection = false;
+			config.m_minRayToBackgroundDistance = kMaxF32;
 		}
 		}
-	}
 
 
-	// Reject far from hit point
-	if(kExtraSsrRejection)
-	{
-		const Vec3 reflRayHitPointVSpace =
-			cheapPerspectiveUnprojection(g_globalRendererConstants.m_matrices.m_unprojectionParameters, uvToNdc(hitPoint.xy), hitPoint.z);
-		const F32 rejectionMeters = smoothstep(0.1f, 0.6f, roughness);
-		const F32 diff = min(rejectionMeters, length(reflRayHitPointVSpace - viewHitPoint));
-		const F32 distAttenuation = 1.0f - smoothstep(0.0f, rejectionMeters, diff);
-		attenuation *= distAttenuation;
-		if(attenuation < kLowAttenuation)
+		SampleNormalFunc sampleNormalFunc;
+		const Bool success =
+			raymarchGroundTruth<SampleNormalFunc>(viewPos, viewReflDir, uv, depth, g_globalRendererConstants.m_matrices.m_projMat00_11_22_23,
+												  g_globalRendererConstants.m_matrices.m_unprojectionParameters, g_downscaledDepthTex,
+												  g_trilinearClampSampler, config, sampleNormalFunc, viewHitPoint, hitUv, hitDepth);
+
+		if(!success)
 		{
 		{
-			return;
+			return false;
 		}
 		}
 	}
 	}
 
 
 	// Read the reflection
 	// Read the reflection
+	if(!SSR_SAMPLE_GBUFFER)
 	{
 	{
-		if(!SSR_SAMPLE_GBUFFER)
-		{
-			// Reproject the hit point because you are reading the previous frame
-			const Vec4 v4 = mul(g_globalRendererConstants.m_matrices.m_reprojection, Vec4(uvToNdc(hitPoint.xy), hitPoint.z, 1.0));
-			hitPoint.xy = ndcToUv(v4.xy / v4.w);
+		// Reproject the hit point because you are reading the previous frame
+		const Vec4 v4 = mul(g_globalRendererConstants.m_matrices.m_reprojection, Vec4(uvToNdc(hitUv), hitDepth, 1.0));
+		hitUv = ndcToUv(v4.xy / v4.w);
 
 
-			// Read the light buffer
-			const Vec3 ssrColor = g_lightBufferRt.SampleLevel(g_trilinearClampSampler, hitPoint.xy, 0.0).rgb;
-			outColor = clamp(ssrColor, 0.0, kMaxF32); // Fix the value just in case
-		}
-		else
-		{
-			outColor = doLightShading(mul(g_globalRendererConstants.m_matrices.m_cameraTransform, Vec4(viewHitPoint, 1.0)), viewHitPoint,
-									  hitPoint.xy * logicalViewportSize, depth1);
-		}
+		// Read the light buffer
+		const Vec3 ssrColor = g_lightBufferRt.SampleLevel(g_trilinearClampSampler, hitUv, 0.0).rgb;
+		outColor = clamp(ssrColor, 0.0, kMaxF32); // Fix the value just in case
 	}
 	}
+	else
+	{
+		const Vec3 worldPos = mul(g_globalRendererConstants.m_matrices.m_cameraTransform, Vec4(viewHitPoint, 1.0));
+		outColor = doLightShading(worldPos, viewHitPoint, hitUv * logicalViewportSize, hitDepth);
+	}
+
+	return true;
 }
 }
 
 
 // Find if a neghbour is closer and we can use it
 // Find if a neghbour is closer and we can use it
@@ -359,7 +352,7 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 {
 {
 	const IVec2 svGroupThreadId2 = clamp(svGroupThreadId + offset, 0, NUM_THREADS_SQRT - 1);
 	const IVec2 svGroupThreadId2 = clamp(svGroupThreadId + offset, 0, NUM_THREADS_SQRT - 1);
 
 
-	if(g_viewHitPointAndAttenuation[svGroupThreadId2.x][svGroupThreadId2.y].w < kLowAttenuation)
+	if(!g_viewHitPointAndSsrSuccess[svGroupThreadId2.x][svGroupThreadId2.y].w)
 	{
 	{
 		return;
 		return;
 	}
 	}
@@ -442,7 +435,7 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 	Vec3 viewReflDir;
 	Vec3 viewReflDir;
 	Vec3 viewHitPoint;
 	Vec3 viewHitPoint;
 	F32 pdf;
 	F32 pdf;
-	F32 ssrAttenuation;
+	Bool ssrSuccess;
 	if(bSampleGiProbes)
 	if(bSampleGiProbes)
 	{
 	{
 		viewReflDir = reflect(-viewDir, viewNormal);
 		viewReflDir = reflect(-viewDir, viewNormal);
@@ -458,7 +451,7 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 
 
 		viewHitPoint = viewPos + viewReflDir * 1.0;
 		viewHitPoint = viewPos + viewReflDir * 1.0;
 		pdf = kPdfForVeryRough;
 		pdf = kPdfForVeryRough;
-		ssrAttenuation = 1.0;
+		ssrSuccess = true;
 	}
 	}
 	else
 	else
 	{
 	{
@@ -473,14 +466,14 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 			viewReflDir = sampleReflectionVectorIsotropic(viewDir, viewNormal, roughness, randFactors, 4, pdf);
 			viewReflDir = sampleReflectionVectorIsotropic(viewDir, viewNormal, roughness, randFactors, 4, pdf);
 		}
 		}
 
 
-		doSsr(halfViewportSize * UVec2(2, 1), realCoord, logicalCoord, uv, viewPos, depth, randFactors.x, roughness, viewReflDir, ssrAttenuation,
-			  outColor, viewHitPoint);
+		ssrSuccess = doSsr(halfViewportSize * UVec2(2, 1), realCoord, logicalCoord, uv, viewPos, depth, randFactors.x, roughness, viewReflDir,
+						   outColor, viewHitPoint);
 	}
 	}
 
 
 	// Stash to groupshared
 	// Stash to groupshared
 	if(kSsrHallucinate)
 	if(kSsrHallucinate)
 	{
 	{
-		g_viewHitPointAndAttenuation[svGroupThreadId.x][svGroupThreadId.y] = Vec4(viewHitPoint, ssrAttenuation);
+		g_viewHitPointAndSsrSuccess[svGroupThreadId.x][svGroupThreadId.y] = Vec4(viewHitPoint, ssrSuccess);
 		g_colorAndDepth[svGroupThreadId.x][svGroupThreadId.y] = Vec4(outColor, depth);
 		g_colorAndDepth[svGroupThreadId.x][svGroupThreadId.y] = Vec4(outColor, depth);
 		GroupMemoryBarrierWithGroupSync();
 		GroupMemoryBarrierWithGroupSync();
 	}
 	}
@@ -494,7 +487,7 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 	}
 	}
 
 
 	// Hallucinate if needed
 	// Hallucinate if needed
-	if(ssrAttenuation <= kLowAttenuation && kSsrHallucinate)
+	if(!ssrSuccess && kSsrHallucinate)
 	{
 	{
 		IVec2 neighbourOffset = -100;
 		IVec2 neighbourOffset = -100;
 		F32 depthWeight = 0.0;
 		F32 depthWeight = 0.0;
@@ -511,14 +504,14 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 
 
 			const UVec2 neighbourSvGroupThreadId = svGroupThreadId + neighbourOffset;
 			const UVec2 neighbourSvGroupThreadId = svGroupThreadId + neighbourOffset;
 
 
-			viewHitPoint = g_viewHitPointAndAttenuation[neighbourSvGroupThreadId.x][neighbourSvGroupThreadId.y].xyz;
+			viewHitPoint = g_viewHitPointAndSsrSuccess[neighbourSvGroupThreadId.x][neighbourSvGroupThreadId.y].xyz;
 
 
 			viewReflDir = normalize(viewHitPoint - viewPos);
 			viewReflDir = normalize(viewHitPoint - viewPos);
 			const Vec3 viewDir = normalize(-viewPos);
 			const Vec3 viewDir = normalize(-viewPos);
 			const F32 alpha = pow2(roughness);
 			const F32 alpha = pow2(roughness);
 			pdf = pdfVndfIsotropic(viewReflDir, viewDir, alpha, viewNormal);
 			pdf = pdfVndfIsotropic(viewReflDir, viewDir, alpha, viewNormal);
 
 
-			ssrAttenuation = g_viewHitPointAndAttenuation[neighbourSvGroupThreadId.x][neighbourSvGroupThreadId.y].w;
+			ssrSuccess = g_viewHitPointAndSsrSuccess[neighbourSvGroupThreadId.x][neighbourSvGroupThreadId.y].w;
 
 
 			outColor = g_colorAndDepth[neighbourSvGroupThreadId.x][neighbourSvGroupThreadId.y].xyz;
 			outColor = g_colorAndDepth[neighbourSvGroupThreadId.x][neighbourSvGroupThreadId.y].xyz;
 
 
@@ -530,7 +523,7 @@ void bestCandidateToHallucinate(IVec2 svGroupThreadId, IVec2 offset, F32 depth,
 	}
 	}
 
 
 	// Complete
 	// Complete
-	if(ssrAttenuation > kLowAttenuation)
+	if(ssrSuccess)
 	{
 	{
 		// Write to the image
 		// Write to the image
 
 

+ 78 - 33
AnKi/Shaders/SsRaymarching.hlsl

@@ -9,6 +9,12 @@
 
 
 #include <AnKi/Shaders/Functions.hlsl>
 #include <AnKi/Shaders/Functions.hlsl>
 
 
+// If the angle between the reflection and the normal grows more than 90 deg than the return value turns to zero
+F32 rejectBackFaces(Vec3 reflection, Vec3 normalAtHitPoint)
+{
+	return smoothstep(-0.17, 0.0, dot(normalAtHitPoint, -reflection));
+}
+
 // Find the intersection of a ray and a AABB when the ray is inside the AABB
 // Find the intersection of a ray and a AABB when the ray is inside the AABB
 void rayAabbIntersectionInside2d(Vec2 rayOrigin, Vec2 rayDir, Vec2 aabbMin, Vec2 aabbMax, out F32 t)
 void rayAabbIntersectionInside2d(Vec2 rayOrigin, Vec2 rayDir, Vec2 aabbMin, Vec2 aabbMax, out F32 t)
 {
 {
@@ -143,38 +149,59 @@ void raymarch(Vec3 rayOrigin, // Ray origin in view space
 	hitPoint = origin;
 	hitPoint = origin;
 }
 }
 
 
+struct RayMarchingConfig
+{
+	U32 m_maxIterations; // The max iterations of the base algorithm
+	F32 m_depthTextureLod; // LOD to pass to the SampleLevel of the depth texture
+	U32 m_stepIncrement; // The step increment of each iteration
+	U32 m_initialStepIncrement; // The initial step
+
+	Bool m_backfaceRejection; // If it's zero then no rejection will happen
+	F32 m_minRayToBackgroundDistance; // Distance between the hit point on the ray and the hit point that is touching the depth buffer.
+									  // Make it kMaxF32 to disable the test
+};
+
+struct DummySampleNormalFunc
+{
+	Vec3 sample(Vec2 uv)
+	{
+		return 0.0;
+	}
+};
+
 // Note: All calculations in view space
 // Note: All calculations in view space
-void raymarchGroundTruth(Vec3 rayOrigin, // Ray origin in view space
+template<typename TSampleNormalFunc>
+Bool raymarchGroundTruth(Vec3 rayOrigin, // Ray origin in view space
 						 Vec3 rayDir, // Ray dir in view space
 						 Vec3 rayDir, // Ray dir in view space
 						 Vec2 uv, // UV the ray starts
 						 Vec2 uv, // UV the ray starts
 						 F32 depthRef, // Depth the ray starts
 						 F32 depthRef, // Depth the ray starts
 						 Vec4 projMat00_11_22_23, // Projection matrix
 						 Vec4 projMat00_11_22_23, // Projection matrix
-						 U32 maxIterations, // The max iterations of the base algorithm
+						 Vec4 unprojectionParams,
 						 Texture2D<Vec4> depthTex, // Depth tex
 						 Texture2D<Vec4> depthTex, // Depth tex
 						 SamplerState depthSampler, // Sampler for depthTex
 						 SamplerState depthSampler, // Sampler for depthTex
-						 F32 depthLod, // LOD to pass to the textureLod
-						 U32 stepIncrement_, // The step increment of each iteration
-						 U32 initialStepIncrement, // The initial step
-						 out Vec3 hitPoint, // Hit point in UV coordinates
-						 out F32 attenuation)
+						 RayMarchingConfig config,
+						 TSampleNormalFunc sampleNormalFunc, // Only used if m_backfaceRejection is true
+						 out Vec3 hitPoint, // Hit point in view space
+						 out Vec2 hitUv, out F32 hitDepth)
 {
 {
-	attenuation = 0.0;
-	hitPoint = Vec3(uv, depthRef);
+	hitPoint = rayOrigin;
+	hitUv = uv;
+	hitDepth = 0.0;
 
 
 	// Check for view facing reflections [sakibsaikia]
 	// Check for view facing reflections [sakibsaikia]
 	const Vec3 viewDir = normalize(rayOrigin);
 	const Vec3 viewDir = normalize(rayOrigin);
 	const F32 cameraContribution = 1.0 - smoothstep(0.25, 0.5, dot(-viewDir, rayDir));
 	const F32 cameraContribution = 1.0 - smoothstep(0.25, 0.5, dot(-viewDir, rayDir));
 	if(cameraContribution <= 0.0)
 	if(cameraContribution <= 0.0)
 	{
 	{
-		return;
+		return false;
 	}
 	}
 
 
 	// Find the depth's mipmap size
 	// Find the depth's mipmap size
 	UVec2 depthTexSize;
 	UVec2 depthTexSize;
 	U32 depthTexMipCount;
 	U32 depthTexMipCount;
 	depthTex.GetDimensions(0u, depthTexSize.x, depthTexSize.y, depthTexMipCount);
 	depthTex.GetDimensions(0u, depthTexSize.x, depthTexSize.y, depthTexMipCount);
-	depthLod = min(depthLod, F32(depthTexMipCount) - 1.0f);
-	const UVec2 depthTexMipSize = depthTexSize >> U32(depthLod);
+	config.m_depthTextureLod = min(config.m_depthTextureLod, F32(depthTexMipCount) - 1.0f);
+	const UVec2 depthTexMipSize = depthTexSize >> U32(config.m_depthTextureLod);
 
 
 	// Start point
 	// Start point
 	const Vec3 start = Vec3(uv, depthRef);
 	const Vec3 start = Vec3(uv, depthRef);
@@ -193,27 +220,32 @@ void raymarchGroundTruth(Vec3 rayOrigin, // Ray origin in view space
 	const F32 stepSize = 1.0 / ((dir.x > dir.y) ? depthTexMipSize.x : depthTexMipSize.y);
 	const F32 stepSize = 1.0 / ((dir.x > dir.y) ? depthTexMipSize.x : depthTexMipSize.y);
 
 
 	// Compute step
 	// Compute step
-	I32 stepIncrement = I32(stepIncrement_);
-	I32 crntStep = I32(initialStepIncrement);
+	I32 stepIncrement = I32(config.m_stepIncrement);
+	I32 crntStep = I32(config.m_initialStepIncrement);
 
 
 	// Search
 	// Search
-	[loop] while(maxIterations-- != 0u)
+	[loop] while(config.m_maxIterations-- != 0u)
 	{
 	{
 		const Vec3 newHit = start + dir * (F32(crntStep) * stepSize);
 		const Vec3 newHit = start + dir * (F32(crntStep) * stepSize);
 
 
 		// Check if it's out of the view
 		// Check if it's out of the view
 		if(any(newHit <= 0.0) || any(newHit >= 1.0))
 		if(any(newHit <= 0.0) || any(newHit >= 1.0))
 		{
 		{
-			hitPoint = start;
-			break;
+			return false;
 		}
 		}
 
 
-		const F32 depth = depthTex.SampleLevel(depthSampler, newHit.xy, depthLod).r;
+		const F32 depth = depthTex.SampleLevel(depthSampler, newHit.xy, config.m_depthTextureLod).r;
 		const Bool hit = newHit.z >= depth;
 		const Bool hit = newHit.z >= depth;
+
+		// Move the hit point to where the depth is
+		Vec3 newHitPoint = cheapPerspectiveUnprojection(unprojectionParams, uvToNdc(newHit.xy), newHit.z);
+
 		if(!hit)
 		if(!hit)
 		{
 		{
 			crntStep += stepIncrement;
 			crntStep += stepIncrement;
-			hitPoint = newHit;
+			hitPoint = newHitPoint;
+			hitUv = newHit.xy;
+			hitDepth = depth;
 		}
 		}
 		else if(stepIncrement > 1)
 		else if(stepIncrement > 1)
 		{
 		{
@@ -224,24 +256,37 @@ void raymarchGroundTruth(Vec3 rayOrigin, // Ray origin in view space
 		}
 		}
 		else
 		else
 		{
 		{
-			// Found it
+			// Maybe found it
 
 
-			// Compute attenuation
-			const F32 blackMargin = 0.05 / 4.0;
-			const F32 whiteMargin = 0.1 / 2.0;
-			const Vec2 marginAttenuation2d =
-				smoothstep(blackMargin, whiteMargin, newHit.xy) * (1.0 - smoothstep(1.0 - whiteMargin, 1.0 - blackMargin, newHit.xy));
-			const F32 marginAttenuation = marginAttenuation2d.x * marginAttenuation2d.y;
-			attenuation = marginAttenuation * cameraContribution;
+			if(config.m_backfaceRejection)
+			{
+				const Vec3 hitNormal = sampleNormalFunc.sample(newHit.xy);
+				const F32 backFaceAttenuation = rejectBackFaces(rayDir, hitNormal);
+				if(backFaceAttenuation <= 0.5)
+				{
+					return false;
+				}
+			}
 
 
-			hitPoint = newHit;
+			if(config.m_minRayToBackgroundDistance < kMaxF32)
+			{
+				const Vec3 pointInDepth = cheapPerspectiveUnprojection(unprojectionParams, uvToNdc(newHit.xy), depth);
+				const F32 dist = length(newHitPoint - pointInDepth);
+				if(dist > config.m_minRayToBackgroundDistance)
+				{
+					return false;
+				}
+
+				newHitPoint = pointInDepth;
+			}
 
 
-			break;
+			// Found it
+			hitPoint = newHitPoint;
+			hitUv = newHit.xy;
+			hitDepth = depth;
+			return true;
 		}
 		}
 	}
 	}
-}
 
 
-void rejectBackFaces(Vec3 reflection, Vec3 normalAtHitPoint, out F32 attenuation)
-{
-	attenuation = smoothstep(-0.17, 0.0, dot(normalAtHitPoint, -reflection));
+	return false;
 }
 }