Browse Source

Convert IndirectSpecular to HLSL

Panagiotis Christopoulos Charitos 2 years ago
parent
commit
3548aae383

+ 0 - 263
AnKi/Shaders/IndirectSpecular.glsl

@@ -1,263 +0,0 @@
-// 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 STOCHASTIC 0 1
-#pragma anki mutator EXTRA_REJECTION 0 1
-
-#include <AnKi/Shaders/LightFunctions.glsl>
-#include <AnKi/Shaders/PackFunctions.glsl>
-#include <AnKi/Shaders/Include/MiscRendererTypes.h>
-#include <AnKi/Shaders/TonemappingFunctions.glsl>
-#include <AnKi/Shaders/SsRaymarching.glsl>
-
-layout(set = 0, binding = 0, row_major) uniform b_unis
-{
-	SsrUniforms u_unis;
-};
-
-layout(set = 0, binding = 1) uniform sampler u_trilinearClampSampler;
-layout(set = 0, binding = 2) uniform ANKI_RP texture2D u_gbufferRt1;
-layout(set = 0, binding = 3) uniform ANKI_RP texture2D u_gbufferRt2;
-layout(set = 0, binding = 4) uniform texture2D u_depthRt;
-layout(set = 0, binding = 5) uniform ANKI_RP texture2D u_lightBufferRt;
-
-layout(set = 0, binding = 6) uniform ANKI_RP texture2D u_historyTex;
-layout(set = 0, binding = 7) uniform texture2D u_motionVectorsTex;
-layout(set = 0, binding = 8) uniform ANKI_RP texture2D u_historyLengthTex;
-
-layout(set = 0, binding = 9) uniform sampler u_trilinearRepeatSampler;
-layout(set = 0, binding = 10) uniform ANKI_RP texture2D u_noiseTex;
-const Vec2 NOISE_TEX_SIZE = Vec2(64.0);
-
-#define CLUSTERED_SHADING_SET 0u
-#define CLUSTERED_SHADING_UNIFORMS_BINDING 11u
-#define CLUSTERED_SHADING_REFLECTIONS_BINDING 12u
-#define CLUSTERED_SHADING_CLUSTERS_BINDING 14u
-#include <AnKi/Shaders/ClusteredShadingCommon.glsl>
-
-#if defined(ANKI_COMPUTE_SHADER)
-const UVec2 kWorkgroupSize = UVec2(8, 8);
-layout(local_size_x = kWorkgroupSize.x, local_size_y = kWorkgroupSize.y, local_size_z = 1) in;
-
-layout(set = 0, binding = 15) uniform writeonly image2D u_outImg;
-#else
-layout(location = 0) in Vec2 in_uv;
-layout(location = 0) out Vec3 out_color;
-#endif
-
-void main()
-{
-#if defined(ANKI_COMPUTE_SHADER)
-	if(skipOutOfBoundsInvocations(kWorkgroupSize, u_unis.m_framebufferSize))
-	{
-		return;
-	}
-	const Vec2 uv = (Vec2(gl_GlobalInvocationID.xy) + 0.5) / Vec2(u_unis.m_framebufferSize);
-#else
-	const Vec2 uv = in_uv;
-#endif
-
-	// Read part of the G-buffer
-	const F32 roughness = unpackRoughnessFromGBuffer(textureLod(u_gbufferRt1, u_trilinearClampSampler, uv, 0.0));
-	const Vec3 worldNormal = unpackNormalFromGBuffer(textureLod(u_gbufferRt2, u_trilinearClampSampler, uv, 0.0));
-
-	// Get depth
-	const F32 depth = textureLod(u_depthRt, u_trilinearClampSampler, uv, 0.0).r;
-
-	// Rand idx
-	const Vec2 noiseUv = Vec2(u_unis.m_framebufferSize) / NOISE_TEX_SIZE * uv;
-	const Vec3 noise =
-		animateBlueNoise(textureLod(u_noiseTex, u_trilinearRepeatSampler, noiseUv, 0.0).rgb, u_unis.m_frameCount % 8u);
-
-	// Get view pos
-	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_unis.m_normalMat * Vec4(worldNormal, 0.0);
-#if STOCHASTIC
-	const Vec3 reflDir = sampleReflectionVector(viewDir, viewNormal, roughness, noise.xy);
-#else
-	const Vec3 reflDir = reflect(-viewDir, viewNormal);
-#endif
-
-	// Is rough enough to deserve SSR?
-	F32 ssrAttenuation = saturate(1.0f - pow(roughness / u_unis.m_roughnessCutoff, 16.0f));
-
-	// Do the heavy work
-	Vec3 hitPoint;
-	if(ssrAttenuation > kEpsilonf)
-	{
-		const U32 lod = 8u; // Use the max LOD for ray marching
-		const U32 step = u_unis.m_firstStepPixels;
-		const F32 stepf = F32(step);
-		const F32 minStepf = stepf / 4.0;
-		F32 hitAttenuation;
-		raymarchGroundTruth(viewPos, reflDir, uv, depth, u_unis.m_projMat, u_unis.m_maxSteps, u_depthRt,
-							u_trilinearClampSampler, F32(lod), u_unis.m_depthBufferSize, step,
-							U32((stepf - minStepf) * noise.x + minStepf), hitPoint, hitAttenuation);
-
-		ssrAttenuation *= hitAttenuation;
-	}
-	else
-	{
-		ssrAttenuation = 0.0f;
-	}
-
-#if EXTRA_REJECTION
-	// Reject backfacing
-	[branch] if(ssrAttenuation > 0.0)
-	{
-		const Vec3 hitNormal =
-			u_unis.m_normalMat
-			* Vec4(unpackNormalFromGBuffer(textureLod(u_gbufferRt2, u_trilinearClampSampler, hitPoint.xy, 0.0)), 0.0);
-		F32 backFaceAttenuation;
-		rejectBackFaces(reflDir, hitNormal, backFaceAttenuation);
-
-		ssrAttenuation *= backFaceAttenuation;
-	}
-
-	// Reject far from hit point
-	[branch] if(ssrAttenuation > 0.0)
-	{
-		const F32 depth = textureLod(u_depthRt, u_trilinearClampSampler, hitPoint.xy, 0.0).r;
-		Vec4 viewPos4 = u_unis.m_invProjMat * Vec4(UV_TO_NDC(hitPoint.xy), depth, 1.0);
-		const F32 actualZ = viewPos4.z / viewPos4.w;
-
-		viewPos4 = u_unis.m_invProjMat * Vec4(UV_TO_NDC(hitPoint.xy), hitPoint.z, 1.0);
-		const F32 hitZ = viewPos4.z / viewPos4.w;
-
-		const F32 rejectionMeters = 1.0;
-		const F32 diff = abs(actualZ - hitZ);
-		const F32 distAttenuation = (diff < rejectionMeters) ? 1.0 : 0.0;
-		ssrAttenuation *= distAttenuation;
-	}
-#endif
-
-	// Read the reflection
-	Vec3 outColor = Vec3(0.0);
-	[branch] if(ssrAttenuation > 0.0)
-	{
-		// 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);
-
-#if STOCHASTIC
-		// LOD stays 0
-		const F32 lod = 0.0;
-#else
-		// Compute the LOD based on the roughness
-		const F32 lod = F32(u_unis.m_lightBufferMipCount - 1u) * roughness;
-#endif
-
-		// Read the light buffer
-		Vec3 ssrColor = textureLod(u_lightBufferRt, u_trilinearClampSampler, hitPoint.xy, lod).rgb;
-		ssrColor = clamp(ssrColor, 0.0, kMaxF32); // Fix the value just in case
-
-		outColor = ssrColor;
-	}
-
-	// Blend with history
-	{
-		const Vec2 historyUv = uv + textureLod(u_motionVectorsTex, u_trilinearClampSampler, uv, 0.0).xy;
-		const F32 historyLength = textureLod(u_historyLengthTex, u_trilinearClampSampler, uv, 0.0).x;
-
-		const F32 lowestBlendFactor = 0.2;
-		const F32 maxHistoryLength = 16.0;
-		const F32 stableFrames = 4.0;
-		const F32 lerp = min(1.0, (historyLength * maxHistoryLength - 1.0) / stableFrames);
-		const F32 blendFactor = mix(1.0, lowestBlendFactor, lerp);
-
-		// Blend with history
-		if(blendFactor < 1.0)
-		{
-			const ANKI_RP Vec3 history = textureLod(u_historyTex, u_trilinearClampSampler, historyUv, 0.0).xyz;
-			outColor = mix(history, outColor, blendFactor);
-		}
-	}
-
-	// Read probes
-	[branch] if(ssrAttenuation < 1.0)
-	{
-#if defined(ANKI_COMPUTE_SHADER)
-		const Vec2 fragCoord = Vec2(gl_GlobalInvocationID.xy) + 0.5;
-#else
-		const Vec2 fragCoord = gl_FragCoord.xy;
-#endif
-
-#if STOCHASTIC
-		const F32 reflLod = 0.0;
-#else
-		const F32 reflLod = (u_clusteredShading.m_reflectionProbesMipCount - 1.0) * roughness;
-#endif
-
-		// Get cluster
-		const Vec2 ndc = UV_TO_NDC(uv);
-		const Vec4 worldPos4 = u_clusteredShading.m_matrices.m_invertedViewProjectionJitter * Vec4(ndc, depth, 1.0);
-		const Vec3 worldPos = worldPos4.xyz / worldPos4.w;
-		Cluster cluster = getClusterFragCoord(Vec3(fragCoord * 2.0, depth));
-
-		// Compute the refl dir in word space this time
-		const ANKI_RP Vec3 viewDir = normalize(u_clusteredShading.m_cameraPosition - worldPos);
-#if STOCHASTIC
-		const Vec3 reflDir = sampleReflectionVector(viewDir, worldNormal, roughness, noise.xy);
-#else
-		const Vec3 reflDir = reflect(-viewDir, worldNormal);
-#endif
-
-		Vec3 probeColor = Vec3(0.0);
-
-		if(bitCount(cluster.m_reflectionProbesMask) == 1)
-		{
-			// Only one probe, do a fast path without blend weight
-
-			const ReflectionProbe probe = u_reflectionProbes[findLSB2(cluster.m_reflectionProbesMask)];
-
-			// Sample
-			const Vec3 cubeUv = intersectProbe(worldPos, reflDir, probe.m_aabbMin, probe.m_aabbMax, probe.m_position);
-			const Vec4 cubeArrUv = Vec4(cubeUv, probe.m_cubemapIndex);
-			probeColor = textureLod(u_reflectionsTex, u_trilinearClampSampler, cubeArrUv, reflLod).rgb;
-		}
-		else
-		{
-			// Zero or more than one probes, do a slow path that blends them together
-
-			F32 totalBlendWeight = kEpsilonf;
-
-			// Loop probes
-			[[dont_unroll]] while(cluster.m_reflectionProbesMask != 0u)
-			{
-				const U32 idx = U32(findLSB2(cluster.m_reflectionProbesMask));
-				cluster.m_reflectionProbesMask &= ~(1u << idx);
-				const ReflectionProbe probe = u_reflectionProbes[idx];
-
-				// Compute blend weight
-				const F32 blendWeight = computeProbeBlendWeight(worldPos, probe.m_aabbMin, probe.m_aabbMax, 0.2);
-				totalBlendWeight += blendWeight;
-
-				// Sample reflections
-				const Vec3 cubeUv =
-					intersectProbe(worldPos, reflDir, probe.m_aabbMin, probe.m_aabbMax, probe.m_position);
-				const Vec4 cubeArrUv = Vec4(cubeUv, probe.m_cubemapIndex);
-				const Vec3 c = textureLod(u_reflectionsTex, u_trilinearClampSampler, cubeArrUv, reflLod).rgb;
-				probeColor += c * blendWeight;
-			}
-
-			// Normalize the colors
-			probeColor /= totalBlendWeight;
-		}
-
-		outColor = mix(probeColor, outColor, ssrAttenuation);
-	}
-
-	// Store
-	ssrAttenuation = saturate(ssrAttenuation);
-#if defined(ANKI_COMPUTE_SHADER)
-	imageStore(u_outImg, IVec2(gl_GlobalInvocationID.xy), Vec4(outColor, 0.0));
-#else
-	out_color = outColor;
-#endif
-}

+ 258 - 0
AnKi/Shaders/IndirectSpecular.hlsl

@@ -0,0 +1,258 @@
+// 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 hlsl
+
+#pragma anki mutator STOCHASTIC 0 1
+#pragma anki mutator EXTRA_REJECTION 0 1
+
+#include <AnKi/Shaders/LightFunctions.hlsl>
+#include <AnKi/Shaders/PackFunctions.hlsl>
+#include <AnKi/Shaders/Include/MiscRendererTypes.h>
+#include <AnKi/Shaders/TonemappingFunctions.hlsl>
+#include <AnKi/Shaders/SsRaymarching.hlsl>
+
+[[vk::binding(0)]] ConstantBuffer<SsrUniforms> g_unis;
+
+[[vk::binding(1)]] SamplerState g_trilinearClampSampler;
+[[vk::binding(2)]] Texture2D<RVec4> g_gbufferRt1;
+[[vk::binding(3)]] Texture2D<RVec4> g_gbufferRt2;
+[[vk::binding(4)]] Texture2D g_depthRt;
+[[vk::binding(5)]] Texture2D<RVec4> g_lightBufferRt;
+
+[[vk::binding(6)]] Texture2D<RVec4> g_historyTex;
+[[vk::binding(7)]] Texture2D g_motionVectorsTex;
+[[vk::binding(8)]] Texture2D<RVec4> g_historyLengthTex;
+
+[[vk::binding(9)]] SamplerState g_trilinearRepeatSampler;
+[[vk::binding(10)]] Texture2D<RVec4> g_noiseTex;
+constexpr Vec2 kNoiseTexSize = 64.0;
+
+#define CLUSTERED_SHADING_SET 0u
+#define CLUSTERED_SHADING_UNIFORMS_BINDING 11u
+#define CLUSTERED_SHADING_REFLECTIONS_BINDING 12u
+#define CLUSTERED_SHADING_CLUSTERS_BINDING 14u
+#include <AnKi/Shaders/ClusteredShadingCommon.hlsl>
+
+#if defined(ANKI_COMPUTE_SHADER)
+[[vk::binding(15)]] RWTexture2D<RVec4> g_outUav;
+#endif
+
+#if defined(ANKI_COMPUTE_SHADER)
+[numthreads(8, 8, 1)] void main(UVec3 svDispatchThreadId : SV_DISPATCHTHREADID)
+#else
+RVec3 main(Vec2 uv : TEXCOORD, Vec4 svPosition : SV_POSITION) : SV_TARGET0
+#endif
+{
+#if defined(ANKI_COMPUTE_SHADER)
+	if(any(svDispatchThreadId.xy >= g_unis.m_framebufferSize))
+	{
+		return;
+	}
+	const Vec2 uv = (Vec2(svDispatchThreadId.xy) + 0.5) / Vec2(g_unis.m_framebufferSize);
+#endif
+
+	// Read part of the G-buffer
+	const F32 roughness = unpackRoughnessFromGBuffer(g_gbufferRt1.SampleLevel(g_trilinearClampSampler, uv, 0.0));
+	const Vec3 worldNormal = unpackNormalFromGBuffer(g_gbufferRt2.SampleLevel(g_trilinearClampSampler, uv, 0.0));
+
+	// Get depth
+	const F32 depth = g_depthRt.SampleLevel(g_trilinearClampSampler, uv, 0.0).r;
+
+	// Rand idx
+	const Vec2 noiseUv = Vec2(g_unis.m_framebufferSize) / kNoiseTexSize * uv;
+	const Vec3 noise =
+		animateBlueNoise(g_noiseTex.SampleLevel(g_trilinearRepeatSampler, noiseUv, 0.0).rgb, g_unis.m_frameCount % 8u);
+
+	// Get view pos
+	const Vec4 viewPos4 = mul(g_unis.m_invProjMat, Vec4(uvToNdc(uv), depth, 1.0));
+	const Vec3 viewPos = viewPos4.xyz / viewPos4.w;
+
+	// Compute refl vector
+	const Vec3 viewDir = -normalize(viewPos);
+	const Vec3 viewNormal = mul(g_unis.m_normalMat, Vec4(worldNormal, 0.0));
+#if STOCHASTIC
+	const Vec3 reflDir = sampleReflectionVector(viewDir, viewNormal, roughness, noise.xy);
+#else
+	const Vec3 reflDir = reflect(-viewDir, viewNormal);
+#endif
+
+	// Is rough enough to deserve SSR?
+	F32 ssrAttenuation = saturate(1.0f - pow(roughness / g_unis.m_roughnessCutoff, 16.0f));
+
+	// Do the heavy work
+	Vec3 hitPoint;
+	if(ssrAttenuation > kEpsilonF32)
+	{
+		const U32 lod = 8u; // Use the max LOD for ray marching
+		const U32 step = g_unis.m_firstStepPixels;
+		const F32 stepf = F32(step);
+		const F32 minStepf = stepf / 4.0;
+		F32 hitAttenuation;
+		raymarchGroundTruth(viewPos, reflDir, uv, depth, g_unis.m_projMat, g_unis.m_maxSteps, g_depthRt,
+							g_trilinearClampSampler, F32(lod), g_unis.m_depthBufferSize, step,
+							U32((stepf - minStepf) * noise.x + minStepf), hitPoint, hitAttenuation);
+
+		ssrAttenuation *= hitAttenuation;
+	}
+	else
+	{
+		ssrAttenuation = 0.0f;
+	}
+
+#if EXTRA_REJECTION
+	// Reject backfacing
+	[branch] if(ssrAttenuation > 0.0)
+	{
+		const Vec3 gbufferNormal =
+			unpackNormalFromGBuffer(g_gbufferRt2.SampleLevel(g_trilinearClampSampler, hitPoint.xy, 0.0));
+		const Vec3 hitNormal = mul(g_unis.m_normalMat, Vec4(gbufferNormal, 0.0));
+		F32 backFaceAttenuation;
+		rejectBackFaces(reflDir, hitNormal, backFaceAttenuation);
+
+		ssrAttenuation *= backFaceAttenuation;
+	}
+
+	// Reject far from hit point
+	[branch] if(ssrAttenuation > 0.0)
+	{
+		const F32 depth = g_depthRt.SampleLevel(g_trilinearClampSampler, hitPoint.xy, 0.0).r;
+		Vec4 viewPos4 = mul(g_unis.m_invProjMat, Vec4(uvToNdc(hitPoint.xy), depth, 1.0));
+		const F32 actualZ = viewPos4.z / viewPos4.w;
+
+		viewPos4 = mul(g_unis.m_invProjMat, Vec4(uvToNdc(hitPoint.xy), hitPoint.z, 1.0));
+		const F32 hitZ = viewPos4.z / viewPos4.w;
+
+		const F32 rejectionMeters = 1.0;
+		const F32 diff = abs(actualZ - hitZ);
+		const F32 distAttenuation = (diff < rejectionMeters) ? 1.0 : 0.0;
+		ssrAttenuation *= distAttenuation;
+	}
+#endif
+
+	// Read the reflection
+	Vec3 outColor = 0.0;
+	[branch] if(ssrAttenuation > 0.0)
+	{
+		// Reproject the UV because you are reading the previous frame
+		const Vec4 v4 = mul(g_unis.m_prevViewProjMatMulInvViewProjMat, Vec4(uvToNdc(hitPoint.xy), hitPoint.z, 1.0));
+		hitPoint.xy = ndcToUv(v4.xy / v4.w);
+
+#if STOCHASTIC
+		// LOD stays 0
+		const F32 lod = 0.0;
+#else
+		// Compute the LOD based on the roughness
+		const F32 lod = F32(g_unis.m_lightBufferMipCount - 1u) * roughness;
+#endif
+
+		// Read the light buffer
+		Vec3 ssrColor = g_lightBufferRt.SampleLevel(g_trilinearClampSampler, hitPoint.xy, lod).rgb;
+		ssrColor = clamp(ssrColor, 0.0, kMaxF32); // Fix the value just in case
+
+		outColor = ssrColor;
+	}
+
+	// Blend with history
+	{
+		const Vec2 historyUv = uv + g_motionVectorsTex.SampleLevel(g_trilinearClampSampler, uv, 0.0).xy;
+		const F32 historyLength = g_historyLengthTex.SampleLevel(g_trilinearClampSampler, uv, 0.0).x;
+
+		const F32 lowestBlendFactor = 0.2;
+		const F32 maxHistoryLength = 16.0;
+		const F32 stableFrames = 4.0;
+		const F32 lerpv = min(1.0, (historyLength * maxHistoryLength - 1.0) / stableFrames);
+		const F32 blendFactor = lerp(1.0, lowestBlendFactor, lerpv);
+
+		// Blend with history
+		if(blendFactor < 1.0)
+		{
+			const RVec3 history = g_historyTex.SampleLevel(g_trilinearClampSampler, historyUv, 0.0).xyz;
+			outColor = lerp(history, outColor, blendFactor);
+		}
+	}
+
+	// Read probes
+	[branch] if(ssrAttenuation < 1.0)
+	{
+#if defined(ANKI_COMPUTE_SHADER)
+		const Vec2 fragCoord = Vec2(svDispatchThreadId.xy) + 0.5;
+#else
+		const Vec2 fragCoord = svPosition.xy;
+#endif
+
+#if STOCHASTIC
+		const F32 reflLod = 0.0;
+#else
+		const F32 reflLod = (g_clusteredShading.m_reflectionProbesMipCount - 1.0) * roughness;
+#endif
+
+		// Get cluster
+		const Vec2 ndc = uvToNdc(uv);
+		const Vec4 worldPos4 = mul(g_clusteredShading.m_matrices.m_invertedViewProjectionJitter, Vec4(ndc, depth, 1.0));
+		const Vec3 worldPos = worldPos4.xyz / worldPos4.w;
+		Cluster cluster = getClusterFragCoord(Vec3(fragCoord * 2.0, depth));
+
+		// Compute the refl dir in word space this time
+		const RVec3 viewDir = normalize(g_clusteredShading.m_cameraPosition - worldPos);
+#if STOCHASTIC
+		const Vec3 reflDir = sampleReflectionVector(viewDir, worldNormal, roughness, noise.xy);
+#else
+		const Vec3 reflDir = reflect(-viewDir, worldNormal);
+#endif
+
+		Vec3 probeColor = 0.0;
+
+		if(countbits(cluster.m_reflectionProbesMask) == 1)
+		{
+			// Only one probe, do a fast path without blend weight
+
+			const ReflectionProbe probe = g_reflectionProbes[firstbitlow2(cluster.m_reflectionProbesMask)];
+
+			// Sample
+			const Vec3 cubeUv = intersectProbe(worldPos, reflDir, probe.m_aabbMin, probe.m_aabbMax, probe.m_position);
+			const Vec4 cubeArrUv = Vec4(cubeUv, probe.m_cubemapIndex);
+			probeColor = g_reflectionsTex.SampleLevel(g_trilinearClampSampler, cubeArrUv, reflLod).rgb;
+		}
+		else
+		{
+			// Zero or more than one probes, do a slow path that blends them together
+
+			F32 totalBlendWeight = kEpsilonF32;
+
+			// Loop probes
+			[loop] while(cluster.m_reflectionProbesMask != 0u)
+			{
+				const U32 idx = U32(firstbitlow2(cluster.m_reflectionProbesMask));
+				cluster.m_reflectionProbesMask &= ~(1u << idx);
+				const ReflectionProbe probe = g_reflectionProbes[idx];
+
+				// Compute blend weight
+				const F32 blendWeight = computeProbeBlendWeight(worldPos, probe.m_aabbMin, probe.m_aabbMax, 0.2);
+				totalBlendWeight += blendWeight;
+
+				// Sample reflections
+				const Vec3 cubeUv =
+					intersectProbe(worldPos, reflDir, probe.m_aabbMin, probe.m_aabbMax, probe.m_position);
+				const Vec4 cubeArrUv = Vec4(cubeUv, probe.m_cubemapIndex);
+				const Vec3 c = g_reflectionsTex.SampleLevel(g_trilinearClampSampler, cubeArrUv, reflLod).rgb;
+				probeColor += c * blendWeight;
+			}
+
+			// Normalize the colors
+			probeColor /= totalBlendWeight;
+		}
+
+		outColor = lerp(probeColor, outColor, ssrAttenuation);
+	}
+
+	// Store
+	ssrAttenuation = saturate(ssrAttenuation);
+#if defined(ANKI_COMPUTE_SHADER)
+	g_outUav[svDispatchThreadId.xy] = RVec4(outColor, 0.0);
+#else
+	return outColor;
+#endif
+}

+ 1 - 1
AnKi/Shaders/IndirectSpecularCompute.ankiprog

@@ -4,5 +4,5 @@
 // http://www.anki3d.org/LICENSE
 
 #pragma anki start comp
-#include <AnKi/Shaders/IndirectSpecular.glsl>
+#include <AnKi/Shaders/IndirectSpecular.hlsl>
 #pragma anki end

+ 2 - 2
AnKi/Shaders/IndirectSpecularRaster.ankiprog

@@ -4,9 +4,9 @@
 // http://www.anki3d.org/LICENSE
 
 #pragma anki start vert
-#include <AnKi/Shaders/QuadVert.glsl>
+#include <AnKi/Shaders/QuadVert.hlsl>
 #pragma anki end
 
 #pragma anki start frag
-#include <AnKi/Shaders/IndirectSpecular.glsl>
+#include <AnKi/Shaders/IndirectSpecular.hlsl>
 #pragma anki end

+ 17 - 16
AnKi/Shaders/SsRaymarching.glsl → AnKi/Shaders/SsRaymarching.hlsl

@@ -7,7 +7,7 @@
 
 #pragma once
 
-#include <AnKi/Shaders/Common.glsl>
+#include <AnKi/Shaders/Common.hlsl>
 
 // 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)
@@ -62,9 +62,11 @@ void raymarch(Vec3 rayOrigin, // Ray origin in view space
 			  Vec2 uv, // UV the ray starts
 			  F32 depthRef, // Depth the ray starts
 			  Mat4 projMat, // Projection matrix
-			  U32 randFrom0To3, U32 maxIterations, texture2D hizTex, sampler hizSampler, U32 hizMipCount,
+			  U32 randFrom0To3, U32 maxIterations, Texture2D hizTex, SamplerState hizSampler, U32 hizMipCount,
 			  UVec2 hizMip0Size, out Vec3 hitPoint, out F32 attenuation)
 {
+	ANKI_MAYBE_UNUSED(uv);
+	ANKI_MAYBE_UNUSED(depthRef);
 	attenuation = 0.0;
 
 	// Check for view facing reflections [sakibsaikia]
@@ -76,7 +78,7 @@ void raymarch(Vec3 rayOrigin, // Ray origin in view space
 	}
 
 	// Dither and set starting pos
-	const F32 bayerMat[4] = F32[](1.0, 4.0, 2.0, 3.0);
+	const F32 bayerMat[4] = {1.0, 4.0, 2.0, 3.0};
 	const Vec3 p0 = rayOrigin + rayDir * (tmin * bayerMat[randFrom0To3]);
 
 	// p1
@@ -84,12 +86,12 @@ void raymarch(Vec3 rayOrigin, // Ray origin in view space
 	const Vec3 p1 = rayOrigin + rayDir * tmax;
 
 	// Compute start & end in clip space (well not clip space since x,y are in [0, 1])
-	Vec4 v4 = projMat * Vec4(p0, 1.0);
+	Vec4 v4 = mul(projMat, Vec4(p0, 1.0));
 	Vec3 start = v4.xyz / v4.w;
-	start.xy = NDC_TO_UV(start.xy);
-	v4 = projMat * Vec4(p1, 1.0);
+	start.xy = ndcToUv(start.xy);
+	v4 = mul(projMat, Vec4(p1, 1.0));
 	Vec3 end = v4.xyz / v4.w;
-	end.xy = NDC_TO_UV(end.xy);
+	end.xy = ndcToUv(end.xy);
 
 	// Ray
 	Vec3 origin = start;
@@ -104,9 +106,9 @@ void raymarch(Vec3 rayOrigin, // Ray origin in view space
 		stepToNextCell(origin, dir, U32(mipLevel), hizMip0Size, newOrigin);
 		origin = newOrigin;
 
-		if(all(greaterThan(origin.xy, Vec2(0.0))) && all(lessThan(origin.xy, Vec2(1.0))))
+		if(all(origin.xy > Vec2(0.0, 0.0)) && all(origin.xy < Vec2(1.0, 1.0)))
 		{
-			const F32 newDepth = textureLod(hizTex, hizSampler, origin.xy, F32(mipLevel)).r;
+			const F32 newDepth = hizTex.SampleLevel(hizSampler, origin.xy, F32(mipLevel)).r;
 
 			if(origin.z < newDepth)
 			{
@@ -148,8 +150,8 @@ void raymarchGroundTruth(Vec3 rayOrigin, // Ray origin in view space
 						 F32 depthRef, // Depth the ray starts
 						 Mat4 projMat, // Projection matrix
 						 U32 maxSteps, // The max iterations of the base algorithm
-						 texture2D depthTex, // Depth tex
-						 sampler depthSampler, // Sampler for depthTex
+						 Texture2D depthTex, // Depth tex
+						 SamplerState depthSampler, // Sampler for depthTex
 						 F32 depthLod, // LOD to pass to the textureLod
 						 UVec2 depthTexSize, // Size of the depthTex
 						 U32 initialStepIncrement, // Initial step increment
@@ -168,14 +170,13 @@ void raymarchGroundTruth(Vec3 rayOrigin, // Ray origin in view space
 	}
 
 	// Start point
-	const Vec3 p0 = rayOrigin;
 	const Vec3 start = Vec3(uv, depthRef);
 
 	// Project end point
 	const Vec3 p1 = rayOrigin + rayDir * 0.1;
-	const Vec4 end4 = projMat * Vec4(p1, 1.0);
+	const Vec4 end4 = mul(projMat, Vec4(p1, 1.0));
 	Vec3 end = end4.xyz / end4.w;
-	end.xy = NDC_TO_UV(end.xy);
+	end.xy = ndcToUv(end.xy);
 
 	// Compute the ray and step size
 	Vec3 dir = end - start;
@@ -189,7 +190,7 @@ void raymarchGroundTruth(Vec3 rayOrigin, // Ray origin in view space
 
 	// Search
 	Vec3 origin;
-	[[dont_unroll]] while(maxSteps-- != 0u)
+	[loop] while(maxSteps-- != 0u)
 	{
 		origin = start + dir * (F32(crntStep) * stepSize);
 
@@ -199,7 +200,7 @@ void raymarchGroundTruth(Vec3 rayOrigin, // Ray origin in view space
 			break;
 		}
 
-		const F32 depth = textureLod(depthTex, depthSampler, origin.xy, depthLod).r;
+		const F32 depth = depthTex.SampleLevel(depthSampler, origin.xy, depthLod).r;
 		const Bool hit = origin.z - depth >= 0.0;
 		if(!hit)
 		{