Browse Source

Remove the clipmap

Panagiotis Christopoulos Charitos 6 years ago
parent
commit
4f88e095b0

+ 7 - 2
shaders/ClusteredShadingCommon.glsl

@@ -95,11 +95,16 @@ layout(std140, row_major, set = LIGHT_SET, binding = LIGHT_FOG_DENSITY_VOLUMES_B
 #endif
 #endif
 
 
 //
 //
-// GI clipmap
+// GI (2)
 //
 //
 #if defined(LIGHT_GLOBAL_ILLUMINATION_BINDING)
 #if defined(LIGHT_GLOBAL_ILLUMINATION_BINDING)
 layout(set = LIGHT_SET, binding = LIGHT_GLOBAL_ILLUMINATION_BINDING) uniform texture3D
 layout(set = LIGHT_SET, binding = LIGHT_GLOBAL_ILLUMINATION_BINDING) uniform texture3D
-	u_globalIlluminationTex[GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT * 6u];
+	u_globalIlluminationTextures[MAX_VISIBLE_GLOBAL_ILLUMINATION_PROBES];
+
+layout(set = LIGHT_SET, binding = LIGHT_GLOBAL_ILLUMINATION_BINDING + 1) uniform ugi_
+{
+	GlobalIlluminationProbe u_giProbes[MAX_VISIBLE_GLOBAL_ILLUMINATION_PROBES];
+};
 #endif
 #endif
 
 
 //
 //

+ 1 - 1
shaders/GBufferPost.glslp

@@ -74,7 +74,7 @@ void main()
 			k * (CLUSTER_COUNT_X * CLUSTER_COUNT_Y) + U32(in_clusterIJ.y) * CLUSTER_COUNT_X + U32(in_clusterIJ.x);
 			k * (CLUSTER_COUNT_X * CLUSTER_COUNT_Y) + U32(in_clusterIJ.y) * CLUSTER_COUNT_X + U32(in_clusterIJ.x);
 
 
 		idxOffset = u_clusters[clusterIdx];
 		idxOffset = u_clusters[clusterIdx];
-		idxOffset = u_lightIndices[idxOffset - 2u]; // Use the offset metadata
+		idxOffset = u_lightIndices[idxOffset - 3u]; // Use the offset metadata
 	}
 	}
 
 
 	// Process decals
 	// Process decals

+ 11 - 8
shaders/IrradianceDice.glslp

@@ -23,7 +23,7 @@ layout(set = 0, binding = 1) uniform texture2D u_lightShadingTex;
 layout(set = 0, binding = 2) uniform texture2D u_gbufferTex0;
 layout(set = 0, binding = 2) uniform texture2D u_gbufferTex0;
 layout(set = 0, binding = 3) uniform texture2D u_gbufferTex1;
 layout(set = 0, binding = 3) uniform texture2D u_gbufferTex1;
 layout(set = 0, binding = 4) uniform texture2D u_gbufferTex2;
 layout(set = 0, binding = 4) uniform texture2D u_gbufferTex2;
-layout(set = 0, binding = 5) uniform writeonly image3D u_irradianceVolumes[6u];
+layout(set = 0, binding = 5) uniform writeonly image3D u_irradianceVolume;
 
 
 // This is a temporary buffer used instead of shared memory because it's too large
 // This is a temporary buffer used instead of shared memory because it's too large
 layout(set = 0, binding = 6, std430) buffer ssbo_
 layout(set = 0, binding = 6, std430) buffer ssbo_
@@ -34,7 +34,7 @@ layout(set = 0, binding = 6, std430) buffer ssbo_
 layout(push_constant, std430) uniform pc_
 layout(push_constant, std430) uniform pc_
 {
 {
 	IVec3 u_volumeTexel;
 	IVec3 u_volumeTexel;
-	I32 u_padding;
+	I32 u_nextTexelOffsetInU;
 };
 };
 
 
 shared Vec3 s_diceIrradiance[6u];
 shared Vec3 s_diceIrradiance[6u];
@@ -157,7 +157,7 @@ void main()
 #endif
 #endif
 
 
 	// Store the results
 	// Store the results
-	ANKI_BRANCH if(gl_LocalInvocationIndex == 0u)
+	if(gl_LocalInvocationIndex == 0u)
 	{
 	{
 		ANKI_UNROLL for(U32 f = 0u; f < 6u; ++f)
 		ANKI_UNROLL for(U32 f = 0u; f < 6u; ++f)
 		{
 		{
@@ -172,14 +172,17 @@ void main()
 #elif DEBUG_MODE == 1
 #elif DEBUG_MODE == 1
 			const Vec3 toStoreValue = colorPerCubeFace(f);
 			const Vec3 toStoreValue = colorPerCubeFace(f);
 #else
 #else
-			const UVec3 volumeSize = UVec3(imageSize(u_irradianceVolumes[0]));
-			const U32 cellIdx =
-				u_volumeTexel.z * volumeSize.x * volumeSize.y + u_volumeTexel.y * volumeSize.x + u_volumeTexel.x;
-			const F32 headmapFactor = F32(cellIdx) / F32(volumeSize.x * volumeSize.y * volumeSize.z);
+			const UVec3 volumeSize = UVec3(imageSize(u_irradianceVolume));
+			const UVec3 subvolumeSize = UVec3(volumeSize.x / 6u, volumeSize.y, volumeSize.z);
+			const U32 cellIdx = u_volumeTexel.z * subvolumeSize.x * subvolumeSize.y + u_volumeTexel.y * subvolumeSize.x
+								+ u_volumeTexel.x;
+			const F32 headmapFactor = F32(cellIdx) / F32(subvolumeSize.x * subvolumeSize.y * subvolumeSize.z);
 			const Vec3 toStoreValue = heatmap(headmapFactor);
 			const Vec3 toStoreValue = heatmap(headmapFactor);
 #endif
 #endif
 
 
-			imageStore(u_irradianceVolumes[f], u_volumeTexel, Vec4(toStoreValue, 0.0));
+			const IVec3 storeUvw =
+				IVec3(u_volumeTexel.x + I32(f) * u_nextTexelOffsetInU, u_volumeTexel.y, u_volumeTexel.z);
+			imageStore(u_irradianceVolume, storeUvw, Vec4(toStoreValue, 0.0));
 		}
 		}
 	}
 	}
 }
 }

+ 0 - 55
shaders/LightFunctions.glsl

@@ -271,58 +271,3 @@ Vec3 sampleAmbientDice(Vec3 posx, Vec3 negx, Vec3 posy, Vec3 negy, Vec3 posz, Ve
 
 
 	return col;
 	return col;
 }
 }
-
-// Given the clipmap bounds find in which level a world position belongs.
-U32 findContainingClipmapLevel(
-	const Vec3 worldPos, const ClipmapLevelInfo clipmapInfos[GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT], out Vec3 uvw)
-{
-	U32 idx;
-	ANKI_UNROLL for(U32 level = 0u; level < GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT; ++level)
-	{
-		const Bool isLast = level == GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT - 1u;
-		const Bool isInside =
-			all(lessThan(worldPos, clipmapInfos[level].m_max)) && all(greaterThan(worldPos, clipmapInfos[level].m_min));
-		if(isInside || isLast)
-		{
-			// Found
-			idx = level;
-
-			// Compute the UVW coordinates inside the level
-			uvw = (worldPos - clipmapInfos[level].m_min) / (clipmapInfos[level].m_max - clipmapInfos[level].m_min);
-			break;
-		}
-	}
-
-	return idx;
-}
-
-// Sample the irradiance term from the clipmap
-Vec3 sampleGlobalIllumination(const Vec3 worldPos,
-	const Vec3 normal,
-	texture3D clipmapTexArray[GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT * 6u],
-	sampler linearAnyClampSampler,
-	const ClipmapLevelInfo clipmapInfos[GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT])
-{
-	// Get the level
-	Vec3 uvw;
-	const U32 level = findContainingClipmapLevel(worldPos, clipmapInfos, uvw);
-
-	// Read the irradiance
-	Vec3 irradiancePerDir[6u];
-	ANKI_UNROLL for(U32 dir = 0u; dir < 6u; ++dir)
-	{
-		irradiancePerDir[dir] =
-			textureLod(clipmapTexArray[nonuniformEXT(level * 6u + dir)], linearAnyClampSampler, uvw, 0.0).rgb;
-	}
-
-	// Sample the irradiance
-	const Vec3 irradiance = sampleAmbientDice(irradiancePerDir[0],
-		irradiancePerDir[1],
-		irradiancePerDir[2],
-		irradiancePerDir[3],
-		irradiancePerDir[4],
-		irradiancePerDir[5],
-		normal);
-
-	return irradiance;
-}

+ 10 - 10
shaders/LightShading.glslp

@@ -38,19 +38,19 @@ void main()
 #define LIGHT_COMMON_UNIS_BINDING 0
 #define LIGHT_COMMON_UNIS_BINDING 0
 #define LIGHT_LIGHTS_BINDING 1
 #define LIGHT_LIGHTS_BINDING 1
 #define LIGHT_INDIRECT_BINDING 4
 #define LIGHT_INDIRECT_BINDING 4
-#define LIGHT_CLUSTERS_BINDING 8
-#define LIGHT_GLOBAL_ILLUMINATION_BINDING 10
+#define LIGHT_GLOBAL_ILLUMINATION_BINDING 8
+#define LIGHT_CLUSTERS_BINDING 10
 #include <shaders/ClusteredShadingCommon.glsl>
 #include <shaders/ClusteredShadingCommon.glsl>
 
 
-layout(set = 0, binding = 11) uniform sampler u_nearestAnyClampSampler;
-layout(set = 0, binding = 12) uniform sampler u_trilinearClampSampler;
+layout(set = 0, binding = 12) uniform sampler u_nearestAnyClampSampler;
+layout(set = 0, binding = 13) uniform sampler u_trilinearClampSampler;
 
 
-layout(set = 0, binding = 13) uniform texture2D u_msRt0;
-layout(set = 0, binding = 14) uniform texture2D u_msRt1;
-layout(set = 0, binding = 15) uniform texture2D u_msRt2;
-layout(set = 0, binding = 16) uniform texture2D u_msDepthRt;
-layout(set = 0, binding = 17) uniform texture2D u_ssrRt;
-layout(set = 0, binding = 18) uniform texture2D u_ssaoRt;
+layout(set = 0, binding = 14) uniform texture2D u_msRt0;
+layout(set = 0, binding = 15) uniform texture2D u_msRt1;
+layout(set = 0, binding = 16) uniform texture2D u_msRt2;
+layout(set = 0, binding = 17) uniform texture2D u_msDepthRt;
+layout(set = 0, binding = 18) uniform texture2D u_ssrRt;
+layout(set = 0, binding = 19) uniform texture2D u_ssaoRt;
 
 
 layout(location = 0) in Vec2 in_uv;
 layout(location = 0) in Vec2 in_uv;
 layout(location = 1) in Vec2 in_clusterIJ;
 layout(location = 1) in Vec2 in_clusterIJ;

+ 10 - 16
shaders/glsl_cpp_common/ClusteredShading.h

@@ -12,12 +12,12 @@
 ANKI_BEGIN_NAMESPACE
 ANKI_BEGIN_NAMESPACE
 
 
 // Consts
 // Consts
-const U32 TYPED_OBJECT_COUNT = 5u;
+const U32 TYPED_OBJECT_COUNT = 6u; // Point lights, spot lights, refl probes, decals, GI probes and fog volumes
 const F32 INVALID_TEXTURE_INDEX = -1.0f;
 const F32 INVALID_TEXTURE_INDEX = -1.0f;
 const F32 LIGHT_FRUSTUM_NEAR_PLANE = 0.1f / 4.0f; // The near plane on the shadow map frustums.
 const F32 LIGHT_FRUSTUM_NEAR_PLANE = 0.1f / 4.0f; // The near plane on the shadow map frustums.
 const U32 MAX_SHADOW_CASCADES = 4u;
 const U32 MAX_SHADOW_CASCADES = 4u;
 const F32 SUBSURFACE_MIN = 0.05f;
 const F32 SUBSURFACE_MIN = 0.05f;
-const U32 GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT = 2u; // Global illumination clipmap count.
+const U32 MAX_VISIBLE_GLOBAL_ILLUMINATION_PROBES = 8u; // Global illumination clipmap count.
 
 
 // See the documentation in the ClustererBin class.
 // See the documentation in the ClustererBin class.
 struct ClustererMagicValues
 struct ClustererMagicValues
@@ -102,26 +102,23 @@ struct FogDensityVolume
 	Vec3 m_aabbMaxOrSphereRadiusSquared;
 	Vec3 m_aabbMaxOrSphereRadiusSquared;
 	F32 m_density;
 	F32 m_density;
 };
 };
-const U32 SIZEOF_FOG_DENSITY_VOLUME = 2 * SIZEOF_VEC4;
+const U32 SIZEOF_FOG_DENSITY_VOLUME = 2u * SIZEOF_VEC4;
 ANKI_SHADER_STATIC_ASSERT(sizeof(FogDensityVolume) == SIZEOF_FOG_DENSITY_VOLUME)
 ANKI_SHADER_STATIC_ASSERT(sizeof(FogDensityVolume) == SIZEOF_FOG_DENSITY_VOLUME)
 
 
 // Global illumination probe
 // Global illumination probe
 struct GlobalIlluminationProbe
 struct GlobalIlluminationProbe
 {
 {
 	Vec3 m_aabbMin;
 	Vec3 m_aabbMin;
-	F32 m_cellSize;
-	Vec3 m_aabbMax;
-	F32 m_padding;
-};
+	U32 m_textureIndex;
 
 
-// Clipmap volume info
-struct ClipmapLevelInfo
-{
-	Vec3 m_min;
+	Vec3 m_aabbMax;
 	F32 m_padding0;
 	F32 m_padding0;
-	Vec3 m_max;
+
+	Vec3 m_halfTexelSize; // (1.0 / giVolumeTextureSize) / 2.0
 	F32 m_padding1;
 	F32 m_padding1;
 };
 };
+const U32 SIZEOF_GLOBAL_ILLUMINATION_PROBE = 3u * SIZEOF_VEC4;
+ANKI_SHADER_STATIC_ASSERT(sizeof(GlobalIlluminationProbe) == SIZEOF_GLOBAL_ILLUMINATION_PROBE)
 
 
 // Common uniforms for light shading passes
 // Common uniforms for light shading passes
 struct LightingUniforms
 struct LightingUniforms
@@ -153,11 +150,8 @@ struct LightingUniforms
 	Mat4 m_prevViewProjMatMulInvViewProjMat; // Used to re-project previous frames
 	Mat4 m_prevViewProjMatMulInvViewProjMat; // Used to re-project previous frames
 
 
 	DirectionalLight m_dirLight;
 	DirectionalLight m_dirLight;
-
-	ClipmapLevelInfo m_globalIlluminationClipmapLevels[GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT];
 };
 };
-const U32 SIZEOF_LIGHTING_UNIFORMS =
-	9 * SIZEOF_VEC4 + 8 * SIZEOF_MAT4 + SIZEOF_DIR_LIGHT + SIZEOF_VEC4 * 2u * GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT;
+const U32 SIZEOF_LIGHTING_UNIFORMS = 9u * SIZEOF_VEC4 + 8u * SIZEOF_MAT4 + SIZEOF_DIR_LIGHT;
 ANKI_SHADER_STATIC_ASSERT(sizeof(LightingUniforms) == SIZEOF_LIGHTING_UNIFORMS)
 ANKI_SHADER_STATIC_ASSERT(sizeof(LightingUniforms) == SIZEOF_LIGHTING_UNIFORMS)
 
 
 ANKI_SHADER_FUNC_INLINE F32 computeClusterKf(ClustererMagicValues magic, Vec3 worldPos)
 ANKI_SHADER_FUNC_INLINE F32 computeClusterKf(ClustererMagicValues magic, Vec3 worldPos)

+ 56 - 3
src/anki/renderer/ClusterBin.cpp

@@ -458,6 +458,32 @@ void ClusterBin::binTile(U32 tileIdx, BinCtx& ctx, TileCtx& tileCtx)
 		}
 		}
 	}
 	}
 
 
+	// GI probes
+	{
+		Aabb probeBox;
+		for(U i = 0; i < ctx.m_in->m_renderQueue->m_giProbes.getSize(); ++i)
+		{
+			const GlobalIlluminationProbeQueueElement& probe = ctx.m_in->m_renderQueue->m_giProbes[i];
+			probeBox.setMin(probe.m_aabbMin);
+			probeBox.setMax(probe.m_aabbMax);
+
+			if(!insideClusterFrustum(frustumPlanes, probeBox))
+			{
+				continue;
+			}
+
+			for(U clusterZ = 0; clusterZ < m_clusterCounts[2]; ++clusterZ)
+			{
+				if(!testCollision(probeBox, clusterBoxes[clusterZ]))
+				{
+					continue;
+				}
+
+				ANKI_SET_IDX(4);
+			}
+		}
+	}
+
 	// Fog volumes
 	// Fog volumes
 	{
 	{
 		for(U i = 0; i < ctx.m_in->m_renderQueue->m_fogDensityVolumes.getSize(); ++i)
 		for(U i = 0; i < ctx.m_in->m_renderQueue->m_fogDensityVolumes.getSize(); ++i)
@@ -482,7 +508,7 @@ void ClusterBin::binTile(U32 tileIdx, BinCtx& ctx, TileCtx& tileCtx)
 						continue;
 						continue;
 					}
 					}
 
 
-					ANKI_SET_IDX(4);
+					ANKI_SET_IDX(5);
 				}
 				}
 			}
 			}
 			else
 			else
@@ -503,7 +529,7 @@ void ClusterBin::binTile(U32 tileIdx, BinCtx& ctx, TileCtx& tileCtx)
 						continue;
 						continue;
 					}
 					}
 
 
-					ANKI_SET_IDX(4);
+					ANKI_SET_IDX(5);
 				}
 				}
 			}
 			}
 		}
 		}
@@ -754,6 +780,33 @@ void ClusterBin::writeTypedObjectsToGpuBuffers(BinCtx& ctx) const
 	{
 	{
 		ctx.m_out->m_fogDensityVolumesToken.markUnused();
 		ctx.m_out->m_fogDensityVolumesToken.markUnused();
 	}
 	}
+
+	// Write the probes
+	const U visibleGiProbeCount = rqueue.m_giProbes.getSize();
+	if(visibleGiProbeCount)
+	{
+		GlobalIlluminationProbe* data = static_cast<GlobalIlluminationProbe*>(
+			ctx.m_in->m_stagingMem->allocateFrame(sizeof(GlobalIlluminationProbe) * visibleGiProbeCount,
+				StagingGpuMemoryType::UNIFORM,
+				ctx.m_out->m_globalIlluminationProbesToken));
+
+		WeakArray<GlobalIlluminationProbe> gpuProbes(data, visibleGiProbeCount);
+
+		for(U i = 0; i < visibleGiProbeCount; ++i)
+		{
+			const GlobalIlluminationProbeQueueElement& in = rqueue.m_giProbes[i];
+			GlobalIlluminationProbe& out = gpuProbes[i];
+
+			out.m_aabbMin = in.m_aabbMin;
+			out.m_aabbMax = in.m_aabbMax;
+			out.m_textureIndex = &in - &rqueue.m_giProbes.getFront();
+			out.m_halfTexelSize = 1.0f / Vec3(in.m_cellCounts.x(), in.m_cellCounts.y(), in.m_cellCounts.z()) * 0.5f;
+		}
+	}
+	else
+	{
+		ctx.m_out->m_globalIlluminationProbesToken.markUnused();
+	}
 }
 }
 
 
-} // end namespace anki
+} // end namespace anki

+ 1 - 0
src/anki/renderer/ClusterBin.h

@@ -41,6 +41,7 @@ public:
 	StagingGpuMemoryToken m_probesToken;
 	StagingGpuMemoryToken m_probesToken;
 	StagingGpuMemoryToken m_decalsToken;
 	StagingGpuMemoryToken m_decalsToken;
 	StagingGpuMemoryToken m_fogDensityVolumesToken;
 	StagingGpuMemoryToken m_fogDensityVolumesToken;
+	StagingGpuMemoryToken m_globalIlluminationProbesToken;
 	StagingGpuMemoryToken m_clustersToken;
 	StagingGpuMemoryToken m_clustersToken;
 	StagingGpuMemoryToken m_indicesToken;
 	StagingGpuMemoryToken m_indicesToken;
 
 

+ 77 - 320
src/anki/renderer/GlobalIllumination.cpp

@@ -28,9 +28,8 @@ static Vec3 computeProbeCellPosition(U cellIdx, const GlobalIlluminationProbeQue
 		cellCoords.y(),
 		cellCoords.y(),
 		cellCoords.x());
 		cellCoords.x());
 
 
-	const F32 halfCellSize = probe.m_cellSize / 2.0f;
-	const Vec3 cellPos =
-		Vec3(cellCoords.x(), cellCoords.y(), cellCoords.z()) * probe.m_cellSize + halfCellSize + probe.m_aabbMin;
+	const Vec3 halfCellSize = probe.m_cellSizes / 2.0f;
+	const Vec3 cellPos = Vec3(cellCoords) * probe.m_cellSizes + halfCellSize + probe.m_aabbMin;
 	ANKI_ASSERT(cellPos < probe.m_aabbMax);
 	ANKI_ASSERT(cellPos < probe.m_aabbMax);
 
 
 	return cellPos;
 	return cellPos;
@@ -39,22 +38,18 @@ static Vec3 computeProbeCellPosition(U cellIdx, const GlobalIlluminationProbeQue
 class GlobalIllumination::InternalContext
 class GlobalIllumination::InternalContext
 {
 {
 public:
 public:
-	GlobalIllumination* m_gi ANKI_DEBUG_CODE(= nullptr);
-	RenderingContext* m_ctx ANKI_DEBUG_CODE(= nullptr);
+	GlobalIllumination* m_gi ANKI_DEBUG_CODE(= numberToPtr<GlobalIllumination*>(1));
+	RenderingContext* m_ctx ANKI_DEBUG_CODE(= numberToPtr<RenderingContext*>(1));
 
 
-	GlobalIlluminationProbeQueueElement* m_probe ANKI_DEBUG_CODE(= nullptr);
-	UVec3 m_cell ANKI_DEBUG_CODE(= UVec3(MAX_U32));
-
-	Array<RenderTargetDescription, GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT> m_clipmapRtDescriptors;
+	GlobalIlluminationProbeQueueElement* m_probeToUpdateThisFrame ANKI_DEBUG_CODE(
+		= numberToPtr<GlobalIlluminationProbeQueueElement*>(1));
+	UVec3 m_cellOfTheProbeToUpdateThisFrame ANKI_DEBUG_CODE(= UVec3(MAX_U32));
 
 
 	Array<RenderTargetHandle, GBUFFER_COLOR_ATTACHMENT_COUNT> m_gbufferColorRts;
 	Array<RenderTargetHandle, GBUFFER_COLOR_ATTACHMENT_COUNT> m_gbufferColorRts;
 	RenderTargetHandle m_gbufferDepthRt;
 	RenderTargetHandle m_gbufferDepthRt;
 	RenderTargetHandle m_shadowsRt;
 	RenderTargetHandle m_shadowsRt;
 	RenderTargetHandle m_lightShadingRt;
 	RenderTargetHandle m_lightShadingRt;
-	Array2d<RenderTargetHandle, GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT, 6> m_clipmapRts;
-
-	Array<Aabb, GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT> m_clipmapLevelAabbs; ///< AABBs in world space.
-	UVec3 m_maxClipmapVolumeSize = UVec3(0u);
+	WeakArray<RenderTargetHandle> m_irradianceProbeRts;
 
 
 	static void foo()
 	static void foo()
 	{
 	{
@@ -66,20 +61,16 @@ GlobalIllumination::~GlobalIllumination()
 {
 {
 	m_cacheEntries.destroy(getAllocator());
 	m_cacheEntries.destroy(getAllocator());
 	m_probeUuidToCacheEntryIdx.destroy(getAllocator());
 	m_probeUuidToCacheEntryIdx.destroy(getAllocator());
-	m_clipmap.m_grProgs.destroy(getAllocator());
 }
 }
 
 
-const Array2d<RenderTargetHandle, GlobalIllumination::GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT, 6>&
-GlobalIllumination::getClipmapVolumeRenderTargets() const
+const RenderTargetHandle& GlobalIllumination::getVolumeRenderTarget(
+	const GlobalIlluminationProbeQueueElement& probe) const
 {
 {
 	ANKI_ASSERT(m_giCtx);
 	ANKI_ASSERT(m_giCtx);
-	return m_giCtx->m_clipmapRts;
-}
-
-const Aabb& GlobalIllumination::getClipmapAabb(U clipmapLevel) const
-{
-	ANKI_ASSERT(m_giCtx);
-	return m_giCtx->m_clipmapLevelAabbs[clipmapLevel];
+	ANKI_ASSERT(&probe >= &m_giCtx->m_ctx->m_renderQueue->m_giProbes.getFront()
+				&& &probe <= &m_giCtx->m_ctx->m_renderQueue->m_giProbes.getBack());
+	const U idx = &probe - &m_giCtx->m_ctx->m_renderQueue->m_giProbes.getFront();
+	return m_giCtx->m_irradianceProbeRts[idx];
 }
 }
 
 
 Error GlobalIllumination::init(const ConfigSet& cfg)
 Error GlobalIllumination::init(const ConfigSet& cfg)
@@ -100,13 +91,13 @@ Error GlobalIllumination::initInternal(const ConfigSet& cfg)
 	m_tileSize = cfg.getNumber("r.gi.tileResolution");
 	m_tileSize = cfg.getNumber("r.gi.tileResolution");
 	m_cacheEntries.create(getAllocator(), cfg.getNumber("r.gi.maxCachedProbes"));
 	m_cacheEntries.create(getAllocator(), cfg.getNumber("r.gi.maxCachedProbes"));
 	m_maxVisibleProbes = cfg.getNumber("r.gi.maxVisibleProbes");
 	m_maxVisibleProbes = cfg.getNumber("r.gi.maxVisibleProbes");
+	ANKI_ASSERT(m_maxVisibleProbes <= MAX_VISIBLE_GLOBAL_ILLUMINATION_PROBES);
 	ANKI_ASSERT(m_cacheEntries.getSize() >= m_maxVisibleProbes);
 	ANKI_ASSERT(m_cacheEntries.getSize() >= m_maxVisibleProbes);
 
 
 	ANKI_CHECK(initGBuffer(cfg));
 	ANKI_CHECK(initGBuffer(cfg));
 	ANKI_CHECK(initLightShading(cfg));
 	ANKI_CHECK(initLightShading(cfg));
 	ANKI_CHECK(initShadowMapping(cfg));
 	ANKI_CHECK(initShadowMapping(cfg));
 	ANKI_CHECK(initIrradiance(cfg));
 	ANKI_CHECK(initIrradiance(cfg));
-	ANKI_CHECK(initClipmap(cfg));
 
 
 	return Error::NONE;
 	return Error::NONE;
 }
 }
@@ -219,41 +210,6 @@ Error GlobalIllumination::initIrradiance(const ConfigSet& cfg)
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-Error GlobalIllumination::initClipmap(const ConfigSet& cfg)
-{
-	// Init the program
-	ANKI_CHECK(
-		m_r->getResourceManager().loadResource("shaders/GlobalIlluminationClipmapPopulation.glslp", m_clipmap.m_prog));
-
-	m_clipmap.m_grProgs.create(getAllocator(), m_maxVisibleProbes + 1);
-
-	ShaderProgramResourceConstantValueInitList<2> consts(m_clipmap.m_prog);
-	consts.add("PROBE_COUNT", U32(0));
-	consts.add("WORKGROUP_SIZE",
-		UVec3(m_clipmap.m_workgroupSize[0], m_clipmap.m_workgroupSize[1], m_clipmap.m_workgroupSize[2]));
-
-	ShaderProgramResourceMutationInitList<1> mutations(m_clipmap.m_prog);
-	mutations.add("HAS_PROBES", 0);
-
-	for(U probeCount = 0; probeCount < m_clipmap.m_grProgs.getSize(); ++probeCount)
-	{
-		const ShaderProgramResourceVariant* variant;
-		consts[0].m_uint = U32(probeCount);
-		mutations[0].m_value = (probeCount > 0);
-		m_clipmap.m_prog->getOrCreateVariant(mutations.get(), consts.get(), variant);
-		m_clipmap.m_grProgs[probeCount] = variant->getProgram();
-	}
-
-	// Init more
-	zeroMemory(m_clipmap.m_volumeSizes);
-	static_assert(GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT == 2, "The following line assume that");
-	m_clipmap.m_cellSizes[0] = cfg.getNumber("r.gi.firstClipmapLevelCellSize");
-	m_clipmap.m_cellSizes[1] = cfg.getNumber("r.gi.secondClipmapLevelCellSize");
-	m_clipmap.m_levelMaxDistances[0] = cfg.getNumber("r.gi.firstClipmapMaxDistance");
-
-	return Error::NONE;
-}
-
 void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 {
 {
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
@@ -265,11 +221,15 @@ void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 	m_giCtx = giCtx;
 	m_giCtx = giCtx;
 
 
 	// Prepare the probes
 	// Prepare the probes
-	prepareProbes(rctx, giCtx->m_probe, giCtx->m_cell);
-	const Bool haveProbeToRender = giCtx->m_probe != nullptr;
+	prepareProbes(*giCtx);
+	const Bool haveProbeToRender = giCtx->m_probeToUpdateThisFrame != nullptr;
+	if(!haveProbeToRender)
+	{
+		// Early exit
+		return;
+	}
 
 
 	// GBuffer
 	// GBuffer
-	if(haveProbeToRender)
 	{
 	{
 		// RTs
 		// RTs
 		for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
 		for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
@@ -299,14 +259,15 @@ void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 	}
 	}
 
 
 	// Shadow pass. Optional
 	// Shadow pass. Optional
-	if(haveProbeToRender && giCtx->m_probe->m_renderQueues[0]->m_directionalLight.m_uuid
-		&& giCtx->m_probe->m_renderQueues[0]->m_directionalLight.m_shadowCascadeCount > 0)
+	if(giCtx->m_probeToUpdateThisFrame->m_renderQueues[0]->m_directionalLight.m_uuid
+		&& giCtx->m_probeToUpdateThisFrame->m_renderQueues[0]->m_directionalLight.m_shadowCascadeCount > 0)
 	{
 	{
 		// Update light matrices
 		// Update light matrices
 		for(U i = 0; i < 6; ++i)
 		for(U i = 0; i < 6; ++i)
 		{
 		{
-			ANKI_ASSERT(giCtx->m_probe->m_renderQueues[i]->m_directionalLight.m_uuid
-						&& giCtx->m_probe->m_renderQueues[i]->m_directionalLight.m_shadowCascadeCount == 1);
+			ANKI_ASSERT(
+				giCtx->m_probeToUpdateThisFrame->m_renderQueues[i]->m_directionalLight.m_uuid
+				&& giCtx->m_probeToUpdateThisFrame->m_renderQueues[i]->m_directionalLight.m_shadowCascadeCount == 1);
 
 
 			const F32 xScale = 1.0f / 6.0f;
 			const F32 xScale = 1.0f / 6.0f;
 			const F32 yScale = 1.0f;
 			const F32 yScale = 1.0f;
@@ -329,7 +290,8 @@ void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 				0.0f,
 				0.0f,
 				1.0f);
 				1.0f);
 
 
-			Mat4& lightMat = giCtx->m_probe->m_renderQueues[i]->m_directionalLight.m_textureMatrices[0];
+			Mat4& lightMat =
+				giCtx->m_probeToUpdateThisFrame->m_renderQueues[i]->m_directionalLight.m_textureMatrices[0];
 			lightMat = atlasMtx * lightMat;
 			lightMat = atlasMtx * lightMat;
 		}
 		}
 
 
@@ -356,7 +318,6 @@ void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 	}
 	}
 
 
 	// Light shading pass
 	// Light shading pass
-	if(haveProbeToRender)
 	{
 	{
 		// RT
 		// RT
 		giCtx->m_lightShadingRt = rgraph.newRenderTarget(m_lightShading.m_rtDescr);
 		giCtx->m_lightShadingRt = rgraph.newRenderTarget(m_lightShading.m_rtDescr);
@@ -389,7 +350,6 @@ void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 	}
 	}
 
 
 	// Irradiance pass. First & 2nd bounce
 	// Irradiance pass. First & 2nd bounce
-	if(haveProbeToRender)
 	{
 	{
 		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("GI IR");
 		ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("GI IR");
 
 
@@ -408,22 +368,15 @@ void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 			pass.newDependency({giCtx->m_gbufferColorRts[i], TextureUsageBit::SAMPLED_COMPUTE});
 			pass.newDependency({giCtx->m_gbufferColorRts[i], TextureUsageBit::SAMPLED_COMPUTE});
 		}
 		}
 
 
-		for(U i = 0; i < 6; ++i)
-		{
-			pass.newDependency({m_cacheEntries[giCtx->m_probe->m_cacheEntryIndex].m_rtHandles[i],
-				TextureUsageBit::IMAGE_COMPUTE_WRITE});
-		}
+		const U probeIdx = giCtx->m_probeToUpdateThisFrame - &giCtx->m_ctx->m_renderQueue->m_giProbes.getFront();
+		pass.newDependency({giCtx->m_irradianceProbeRts[probeIdx], TextureUsageBit::IMAGE_COMPUTE_WRITE});
 	}
 	}
-
-	// Clipmap population
-	populateRenderGraphClipmap(*giCtx);
 }
 }
 
 
-void GlobalIllumination::prepareProbes(RenderingContext& ctx,
-	GlobalIlluminationProbeQueueElement*& probeToUpdateThisFrame,
-	UVec3& probeToUpdateThisFrameCell)
+void GlobalIllumination::prepareProbes(InternalContext& giCtx)
 {
 {
-	probeToUpdateThisFrame = nullptr;
+	RenderingContext& ctx = *giCtx.m_ctx;
+	giCtx.m_probeToUpdateThisFrame = nullptr;
 
 
 	if(ANKI_UNLIKELY(ctx.m_renderQueue->m_giProbes.getSize() == 0))
 	if(ANKI_UNLIKELY(ctx.m_renderQueue->m_giProbes.getSize() == 0))
 	{
 	{
@@ -436,11 +389,13 @@ void GlobalIllumination::prepareProbes(RenderingContext& ctx,
 	// - Find the cache entries for each probe
 	// - Find the cache entries for each probe
 	DynamicArray<GlobalIlluminationProbeQueueElement> newListOfProbes;
 	DynamicArray<GlobalIlluminationProbeQueueElement> newListOfProbes;
 	newListOfProbes.create(ctx.m_tempAllocator, ctx.m_renderQueue->m_giProbes.getSize());
 	newListOfProbes.create(ctx.m_tempAllocator, ctx.m_renderQueue->m_giProbes.getSize());
+	DynamicArray<RenderTargetHandle> volumeRts;
+	volumeRts.create(ctx.m_tempAllocator, ctx.m_renderQueue->m_giProbes.getSize());
 	U newListOfProbeCount = 0;
 	U newListOfProbeCount = 0;
 	Bool foundProbeToUpdateNextFrame = false;
 	Bool foundProbeToUpdateNextFrame = false;
 	for(U32 probeIdx = 0; probeIdx < ctx.m_renderQueue->m_giProbes.getSize(); ++probeIdx)
 	for(U32 probeIdx = 0; probeIdx < ctx.m_renderQueue->m_giProbes.getSize(); ++probeIdx)
 	{
 	{
-		if(probeIdx == m_maxVisibleProbes)
+		if(newListOfProbeCount + 1 >= m_maxVisibleProbes)
 		{
 		{
 			ANKI_R_LOGW("Can't have more that %u visible probes. Increase the r.gi.maxVisibleProbes or (somehow) "
 			ANKI_R_LOGW("Can't have more that %u visible probes. Increase the r.gi.maxVisibleProbes or (somehow) "
 						"decrease the visible probes",
 						"decrease the visible probes",
@@ -473,20 +428,15 @@ void GlobalIllumination::prepareProbes(RenderingContext& ctx,
 			// It's updated, early exit
 			// It's updated, early exit
 
 
 			entry.m_lastUsedTimestamp = m_r->getGlobalTimestamp();
 			entry.m_lastUsedTimestamp = m_r->getGlobalTimestamp();
-			for(U i = 0; i < 6; i++)
-			{
-				entry.m_rtHandles[i] = ctx.m_renderGraphDescr.importRenderTarget(
-					entry.m_volumeTextures[i], TextureUsageBit::SAMPLED_COMPUTE);
-			}
-
-			probe.m_cacheEntryIndex = cacheEntryIdx;
+			volumeRts[newListOfProbeCount] =
+				ctx.m_renderGraphDescr.importRenderTarget(entry.m_volumeTex, TextureUsageBit::SAMPLED_FRAGMENT);
 			newListOfProbes[newListOfProbeCount++] = probe;
 			newListOfProbes[newListOfProbeCount++] = probe;
 			continue;
 			continue;
 		}
 		}
 
 
 		// It needs update
 		// It needs update
 
 
-		const Bool canUpdateThisFrame = probeToUpdateThisFrame == nullptr && probe.m_renderQueues[0] != nullptr;
+		const Bool canUpdateThisFrame = giCtx.m_probeToUpdateThisFrame == nullptr && probe.m_renderQueues[0] != nullptr;
 		const Bool canUpdateNextFrame = !foundProbeToUpdateNextFrame;
 		const Bool canUpdateNextFrame = !foundProbeToUpdateNextFrame;
 
 
 		if(!canUpdateThisFrame && canUpdateNextFrame)
 		if(!canUpdateThisFrame && canUpdateNextFrame)
@@ -521,27 +471,20 @@ void GlobalIllumination::prepareProbes(RenderingContext& ctx,
 		// Update the cache entry
 		// Update the cache entry
 		entry.m_lastUsedTimestamp = m_r->getGlobalTimestamp();
 		entry.m_lastUsedTimestamp = m_r->getGlobalTimestamp();
 
 
-		// Update the probe
-		probe.m_cacheEntryIndex = cacheEntryIdx;
-
 		// Init the cache entry textures
 		// Init the cache entry textures
-		const Bool shouldInitTextures =
-			!entry.m_volumeTextures[0].isCreated() || entry.m_volumeSize != probe.m_cellCounts;
+		const Bool shouldInitTextures = !entry.m_volumeTex.isCreated() || entry.m_volumeSize != probe.m_cellCounts;
 		if(shouldInitTextures)
 		if(shouldInitTextures)
 		{
 		{
 			TextureInitInfo texInit;
 			TextureInitInfo texInit;
 			texInit.m_type = TextureType::_3D;
 			texInit.m_type = TextureType::_3D;
 			texInit.m_format = Format::B10G11R11_UFLOAT_PACK32;
 			texInit.m_format = Format::B10G11R11_UFLOAT_PACK32;
-			texInit.m_width = probe.m_cellCounts.x();
+			texInit.m_width = probe.m_cellCounts.x() * 6;
 			texInit.m_height = probe.m_cellCounts.y();
 			texInit.m_height = probe.m_cellCounts.y();
 			texInit.m_depth = probe.m_cellCounts.z();
 			texInit.m_depth = probe.m_cellCounts.z();
 			texInit.m_usage = TextureUsageBit::ALL_COMPUTE | TextureUsageBit::SAMPLED_ALL;
 			texInit.m_usage = TextureUsageBit::ALL_COMPUTE | TextureUsageBit::SAMPLED_ALL;
 			texInit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
 			texInit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
 
 
-			for(U i = 0; i < 6; ++i)
-			{
-				entry.m_volumeTextures[i] = m_r->createAndClearRenderTarget(texInit);
-			}
+			entry.m_volumeTex = m_r->createAndClearRenderTarget(texInit);
 		}
 		}
 
 
 		// Compute the render position
 		// Compute the render position
@@ -551,9 +494,9 @@ void GlobalIllumination::prepareProbes(RenderingContext& ctx,
 			probe.m_cellCounts.y(),
 			probe.m_cellCounts.y(),
 			probe.m_cellCounts.x(),
 			probe.m_cellCounts.x(),
 			cellToRender,
 			cellToRender,
-			probeToUpdateThisFrameCell.z(),
-			probeToUpdateThisFrameCell.y(),
-			probeToUpdateThisFrameCell.x());
+			giCtx.m_cellOfTheProbeToUpdateThisFrame.z(),
+			giCtx.m_cellOfTheProbeToUpdateThisFrame.y(),
+			giCtx.m_cellOfTheProbeToUpdateThisFrame.x());
 
 
 		// Inform probe about its next frame
 		// Inform probe about its next frame
 		if(entry.m_renderedCells == probe.m_totalCellCount)
 		if(entry.m_renderedCells == probe.m_totalCellCount)
@@ -570,14 +513,11 @@ void GlobalIllumination::prepareProbes(RenderingContext& ctx,
 		}
 		}
 
 
 		// Push the probe to the new list
 		// Push the probe to the new list
-		probeToUpdateThisFrame = &newListOfProbes[newListOfProbeCount];
-		newListOfProbes[newListOfProbeCount++] = probe;
-
-		for(U i = 0; i < 6; i++)
-		{
-			entry.m_rtHandles[i] =
-				ctx.m_renderGraphDescr.importRenderTarget(entry.m_volumeTextures[i], TextureUsageBit::SAMPLED_FRAGMENT);
-		}
+		giCtx.m_probeToUpdateThisFrame = &newListOfProbes[newListOfProbeCount];
+		newListOfProbes[newListOfProbeCount] = probe;
+		volumeRts[newListOfProbeCount] =
+			ctx.m_renderGraphDescr.importRenderTarget(entry.m_volumeTex, TextureUsageBit::SAMPLED_FRAGMENT);
+		++newListOfProbeCount;
 	}
 	}
 
 
 	// Replace the probe list in the queue
 	// Replace the probe list in the queue
@@ -587,20 +527,25 @@ void GlobalIllumination::prepareProbes(RenderingContext& ctx,
 		PtrSize probeCount, storage;
 		PtrSize probeCount, storage;
 		newListOfProbes.moveAndReset(firstProbe, probeCount, storage);
 		newListOfProbes.moveAndReset(firstProbe, probeCount, storage);
 		ctx.m_renderQueue->m_giProbes = WeakArray<GlobalIlluminationProbeQueueElement>(firstProbe, newListOfProbeCount);
 		ctx.m_renderQueue->m_giProbes = WeakArray<GlobalIlluminationProbeQueueElement>(firstProbe, newListOfProbeCount);
+
+		RenderTargetHandle* firstRt;
+		volumeRts.moveAndReset(firstRt, probeCount, storage);
+		m_giCtx->m_irradianceProbeRts = WeakArray<RenderTargetHandle>(firstRt, newListOfProbeCount);
 	}
 	}
 	else
 	else
 	{
 	{
 		ctx.m_renderQueue->m_giProbes = WeakArray<GlobalIlluminationProbeQueueElement>();
 		ctx.m_renderQueue->m_giProbes = WeakArray<GlobalIlluminationProbeQueueElement>();
 		newListOfProbes.destroy(ctx.m_tempAllocator);
 		newListOfProbes.destroy(ctx.m_tempAllocator);
+		volumeRts.destroy(ctx.m_tempAllocator);
 	}
 	}
 }
 }
 
 
 void GlobalIllumination::runGBufferInThread(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx) const
 void GlobalIllumination::runGBufferInThread(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx) const
 {
 {
-	ANKI_ASSERT(giCtx.m_probe);
+	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 
 
-	const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probe;
+	const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probeToUpdateThisFrame;
 	const U faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
 	const U faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
 	ANKI_ASSERT(faceIdx < 6);
 	ANKI_ASSERT(faceIdx < 6);
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
@@ -636,9 +581,9 @@ void GlobalIllumination::runShadowmappingInThread(RenderPassWorkContext& rgraphC
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 	cmdb->setPolygonOffset(1.0f, 1.0f);
 	cmdb->setPolygonOffset(1.0f, 1.0f);
 
 
-	ANKI_ASSERT(giCtx.m_probe);
-	ANKI_ASSERT(giCtx.m_probe->m_renderQueues[faceIdx]);
-	const RenderQueue& faceRenderQueue = *giCtx.m_probe->m_renderQueues[faceIdx];
+	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
+	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame->m_renderQueues[faceIdx]);
+	const RenderQueue& faceRenderQueue = *giCtx.m_probeToUpdateThisFrame->m_renderQueues[faceIdx];
 	ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_uuid != 0);
 	ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_uuid != 0);
 	ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_shadowCascadeCount == 1);
 	ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_shadowCascadeCount == 1);
 
 
@@ -669,8 +614,8 @@ void GlobalIllumination::runLightShading(RenderPassWorkContext& rgraphCtx, Inter
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 
 
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
-	ANKI_ASSERT(giCtx.m_probe);
-	const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probe;
+	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
+	const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probeToUpdateThisFrame;
 	const U faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
 	const U faceIdx = rgraphCtx.m_currentSecondLevelCommandBufferIndex;
 	ANKI_ASSERT(faceIdx < 6);
 	ANKI_ASSERT(faceIdx < 6);
 
 
@@ -722,8 +667,9 @@ void GlobalIllumination::runIrradiance(RenderPassWorkContext& rgraphCtx, Interna
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 	ANKI_TRACE_SCOPED_EVENT(R_GI);
 
 
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
-	ANKI_ASSERT(giCtx.m_probe);
-	const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probe;
+	ANKI_ASSERT(giCtx.m_probeToUpdateThisFrame);
+	const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probeToUpdateThisFrame;
+	const U probeIdx = &probe - &giCtx.m_ctx->m_renderQueue->m_giProbes.getFront();
 
 
 	cmdb->bindShaderProgram(m_irradiance.m_grProg);
 	cmdb->bindShaderProgram(m_irradiance.m_grProg);
 
 
@@ -737,214 +683,25 @@ void GlobalIllumination::runIrradiance(RenderPassWorkContext& rgraphCtx, Interna
 		rgraphCtx.bindColorTexture(0, binding++, giCtx.m_gbufferColorRts[i]);
 		rgraphCtx.bindColorTexture(0, binding++, giCtx.m_gbufferColorRts[i]);
 	}
 	}
 
 
-	for(U i = 0; i < 6; ++i)
-	{
-		rgraphCtx.bindImage(
-			0, binding, m_cacheEntries[probe.m_cacheEntryIndex].m_rtHandles[i], TextureSubresourceInfo(), i);
-	}
-	++binding;
+	rgraphCtx.bindImage(0, binding++, giCtx.m_irradianceProbeRts[probeIdx], TextureSubresourceInfo());
 
 
 	// Bind temporary memory
 	// Bind temporary memory
 	allocateAndBindStorage<void*>(sizeof(Vec4) * 6 * m_tileSize * m_tileSize, cmdb, 0, binding);
 	allocateAndBindStorage<void*>(sizeof(Vec4) * 6 * m_tileSize * m_tileSize, cmdb, 0, binding);
 
 
-	const IVec4 volumeTexel = IVec4(giCtx.m_cell.x(), giCtx.m_cell.y(), giCtx.m_cell.z(), 0);
-	cmdb->setPushConstants(&volumeTexel, sizeof(volumeTexel));
-
-	// Dispatch
-	cmdb->dispatchCompute(1, 1, 1);
-}
-
-void GlobalIllumination::runClipmapPopulation(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx)
-{
-	ANKI_TRACE_SCOPED_EVENT(R_GI);
-
-	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
-
-	// Allocate and bin uniforms
-	struct Clipmap
-	{
-		Vec3 m_aabbMin;
-		F32 m_cellSize;
-		Vec3 m_aabbMax;
-		F32 m_padding0;
-		UVec3 m_cellCounts;
-		U32 m_padding2;
-	};
-
-	struct Unis
-	{
-		Clipmap m_clipmaps[GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT];
-		Vec3 m_cameraPos;
-		U32 m_padding;
-	};
-	Unis* unis = allocateAndBindUniforms<Unis*>(sizeof(Unis), cmdb, 0, 0);
-
-	for(U level = 0; level < GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT; ++level)
-	{
-		unis->m_clipmaps[level].m_aabbMin = giCtx.m_clipmapLevelAabbs[level].getMin().xyz();
-		unis->m_clipmaps[level].m_cellSize = m_clipmap.m_cellSizes[level];
-		unis->m_clipmaps[level].m_aabbMax = giCtx.m_clipmapLevelAabbs[level].getMax().xyz();
-		unis->m_clipmaps[level].m_cellCounts = UVec3(giCtx.m_clipmapRtDescriptors[level].m_width,
-			giCtx.m_clipmapRtDescriptors[level].m_height,
-			giCtx.m_clipmapRtDescriptors[level].m_depth);
-	}
-	unis->m_cameraPos = giCtx.m_ctx->m_renderQueue->m_cameraTransform.getTranslationPart().xyz();
-
-	// Bind out images
-	for(U level = 0; level < GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT; ++level)
-	{
-		for(U dir = 0; dir < 6; ++dir)
-		{
-			rgraphCtx.bindImage(0, 1, giCtx.m_clipmapRts[level][dir], TextureSubresourceInfo(), level * 6 + dir);
-		}
-	}
-
-	const U probeCount = giCtx.m_ctx->m_renderQueue->m_giProbes.getSize();
-	if(probeCount > 0)
+	struct
 	{
 	{
-		// Allocate and bin the probes
-		GlobalIlluminationProbe* probes =
-			allocateAndBindStorage<GlobalIlluminationProbe*>(sizeof(GlobalIlluminationProbe) * probeCount, cmdb, 0, 2);
-		for(U i = 0; i < probeCount; ++i)
-		{
-			const GlobalIlluminationProbeQueueElement& in = giCtx.m_ctx->m_renderQueue->m_giProbes[i];
-			GlobalIlluminationProbe& out = probes[i];
-
-			out.m_aabbMin = in.m_aabbMin;
-			out.m_aabbMax = in.m_aabbMax;
-			out.m_cellSize = in.m_cellSize;
-		}
-
-		// Bind sampler
-		cmdb->bindSampler(0, 3, m_r->getSamplers().m_trilinearClamp);
-
-		// Bind input textures
-		for(U i = 0; i < probeCount; ++i)
-		{
-			const GlobalIlluminationProbeQueueElement& element = giCtx.m_ctx->m_renderQueue->m_giProbes[i];
-
-			for(U dir = 0; dir < 6; ++dir)
-			{
-				const RenderTargetHandle& rt = m_cacheEntries[element.m_cacheEntryIndex].m_rtHandles[dir];
-
-				rgraphCtx.bindColorTexture(0, 4, rt, i * 6 + dir);
-			}
-		}
-	}
+		IVec3 m_volumeTexel;
+		I32 m_nextTexelOffsetInU;
+	} unis;
 
 
-	// Bind the program
-	cmdb->bindShaderProgram(m_clipmap.m_grProgs[giCtx.m_ctx->m_renderQueue->m_giProbes.getSize()]);
+	unis.m_volumeTexel = IVec3(giCtx.m_cellOfTheProbeToUpdateThisFrame.x(),
+		giCtx.m_cellOfTheProbeToUpdateThisFrame.y(),
+		giCtx.m_cellOfTheProbeToUpdateThisFrame.z());
+	unis.m_nextTexelOffsetInU = probe.m_cellCounts.x();
+	cmdb->setPushConstants(&unis, sizeof(unis));
 
 
 	// Dispatch
 	// Dispatch
-	dispatchPPCompute(cmdb,
-		m_clipmap.m_workgroupSize[0],
-		m_clipmap.m_workgroupSize[1],
-		m_clipmap.m_workgroupSize[2],
-		giCtx.m_maxClipmapVolumeSize[0],
-		giCtx.m_maxClipmapVolumeSize[1],
-		giCtx.m_maxClipmapVolumeSize[2]);
-}
-
-void GlobalIllumination::populateRenderGraphClipmap(InternalContext& giCtx)
-{
-	RenderGraphDescription& rgraph = giCtx.m_ctx->m_renderGraphDescr;
-	const RenderQueue& rqueue = *giCtx.m_ctx->m_renderQueue;
-
-	// Compute the size of the clipmap levels
-	for(U level = 0; level < GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT; ++level)
-	{
-		// Get the edges of the sub frustum in local space
-		const F32 near = (level == 0) ? EPSILON : m_clipmap.m_levelMaxDistances[level - 1];
-		const F32 far = (level != GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT - 1) ? m_clipmap.m_levelMaxDistances[level]
-																			   : rqueue.m_cameraFar;
-		Array<Vec4, 8> frustumEdges;
-		computeEdgesOfFrustum(near, rqueue.m_cameraFovX, rqueue.m_cameraFovY, &frustumEdges[0]);
-		computeEdgesOfFrustum(far, rqueue.m_cameraFovX, rqueue.m_cameraFovY, &frustumEdges[4]);
-
-		// Transform the edges to world space
-		for(Vec4& edge : frustumEdges)
-		{
-			edge = rqueue.m_cameraTransform * edge.xyz1();
-		}
-
-		// Compute the AABB
-		giCtx.m_clipmapLevelAabbs[level].setFromPointCloud(reinterpret_cast<Vec3*>(&frustumEdges[0]),
-			frustumEdges.getSize(),
-			sizeof(frustumEdges[0]),
-			sizeof(frustumEdges));
-
-		// Align the AABB to the cell grid
-		Vec3 minv(0.0f), maxv(0.0f);
-		for(U comp = 0; comp < 3; ++comp)
-		{
-			minv[comp] =
-				getAlignedRoundDown(m_clipmap.m_cellSizes[level], giCtx.m_clipmapLevelAabbs[level].getMin()[comp]);
-			maxv[comp] =
-				getAlignedRoundUp(m_clipmap.m_cellSizes[level], giCtx.m_clipmapLevelAabbs[level].getMax()[comp]);
-		}
-
-		// Maximize the size of the volumes to avoid creating new RTs every frame
-		const Vec3 volumeSize = (maxv - minv) / m_clipmap.m_cellSizes[level];
-		m_clipmap.m_volumeSizes[level] = m_clipmap.m_volumeSizes[level].max(UVec3(volumeSize));
-
-		maxv = minv + Vec3(m_clipmap.m_volumeSizes[level]) * m_clipmap.m_cellSizes[level];
-		giCtx.m_clipmapLevelAabbs[level].setMin(minv);
-		giCtx.m_clipmapLevelAabbs[level].setMax(maxv);
-
-		// Compute the max volume size for all levels
-		giCtx.m_maxClipmapVolumeSize = giCtx.m_maxClipmapVolumeSize.max(m_clipmap.m_volumeSizes[level]);
-	}
-
-	// Create a few RT descriptors
-	for(U level = 0; level < GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT; ++level)
-	{
-		RenderTargetDescription& descr = giCtx.m_clipmapRtDescriptors[level];
-
-		descr = m_r->create2DRenderTargetDescription(m_clipmap.m_volumeSizes[level][0],
-			m_clipmap.m_volumeSizes[level][1],
-			Format::B10G11R11_UFLOAT_PACK32,
-			"GI clipmap");
-		descr.m_depth = m_clipmap.m_volumeSizes[level][2];
-		descr.m_type = TextureType::_3D;
-		descr.bake();
-	}
-
-	// Ask for render targets
-	for(U level = 0; level < GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT; ++level)
-	{
-		for(U dir = 0; dir < 6; ++dir)
-		{
-			giCtx.m_clipmapRts[level][dir] = rgraph.newRenderTarget(giCtx.m_clipmapRtDescriptors[level]);
-		}
-	}
-
-	// Create the pass
-	ComputeRenderPassDescription& pass = rgraph.newComputeRenderPass("GI clipmap");
-
-	pass.setWork(
-		[](RenderPassWorkContext& rgraphCtx) {
-			InternalContext* giCtx = static_cast<InternalContext*>(rgraphCtx.m_userData);
-			giCtx->m_gi->runClipmapPopulation(rgraphCtx, *giCtx);
-		},
-		&giCtx,
-		0);
-
-	for(const GlobalIlluminationProbeQueueElement& probe : giCtx.m_ctx->m_renderQueue->m_giProbes)
-	{
-		const CacheEntry& entry = m_cacheEntries[probe.m_cacheEntryIndex];
-		for(U i = 0; i < 6; ++i)
-		{
-			pass.newDependency({entry.m_rtHandles[i], TextureUsageBit::SAMPLED_COMPUTE});
-		}
-	}
-
-	for(U level = 0; level < GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT; ++level)
-	{
-		for(U i = 0; i < 6; ++i)
-		{
-			pass.newDependency({giCtx.m_clipmapRts[level][i], TextureUsageBit::IMAGE_COMPUTE_WRITE});
-		}
-	}
+	cmdb->dispatchCompute(1, 1, 1);
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 4 - 29
src/anki/renderer/GlobalIllumination.h

@@ -21,9 +21,6 @@ namespace anki
 /// It builds a volume clipmap with ambient GI information.
 /// It builds a volume clipmap with ambient GI information.
 class GlobalIllumination : public RendererObject
 class GlobalIllumination : public RendererObject
 {
 {
-private:
-	static constexpr U GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT = 2;
-
 anki_internal:
 anki_internal:
 	GlobalIllumination(Renderer* r)
 	GlobalIllumination(Renderer* r)
 		: RendererObject(r)
 		: RendererObject(r)
@@ -38,12 +35,8 @@ anki_internal:
 	/// Populate the rendergraph.
 	/// Populate the rendergraph.
 	void populateRenderGraph(RenderingContext& ctx);
 	void populateRenderGraph(RenderingContext& ctx);
 
 
-	/// Return a number of volume render targets.
-	const Array2d<RenderTargetHandle, GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT, 6>&
-	getClipmapVolumeRenderTargets() const;
-
-	/// Return the clipmap AABB.
-	const Aabb& getClipmapAabb(U clipmapLevel) const;
+	/// Return the volume RT given a cache entry index.
+	const RenderTargetHandle& getVolumeRenderTarget(const GlobalIlluminationProbeQueueElement& probe) const;
 
 
 private:
 private:
 	class InternalContext;
 	class InternalContext;
@@ -53,12 +46,11 @@ private:
 	public:
 	public:
 		U64 m_uuid; ///< Probe UUID.
 		U64 m_uuid; ///< Probe UUID.
 		Timestamp m_lastUsedTimestamp = 0; ///< When it was last seen by the renderer.
 		Timestamp m_lastUsedTimestamp = 0; ///< When it was last seen by the renderer.
-		Array<TexturePtr, 6> m_volumeTextures; ///< One for the 6 directions of the ambient dice.
+		TexturePtr m_volumeTex; ///< Contains the 6 directions.
 		UVec3 m_volumeSize = UVec3(0u);
 		UVec3 m_volumeSize = UVec3(0u);
 		Vec3 m_probeAabbMin = Vec3(0.0f);
 		Vec3 m_probeAabbMin = Vec3(0.0f);
 		Vec3 m_probeAabbMax = Vec3(0.0f);
 		Vec3 m_probeAabbMax = Vec3(0.0f);
 		U32 m_renderedCells = 0;
 		U32 m_renderedCells = 0;
-		Array<RenderTargetHandle, 6> m_rtHandles;
 	};
 	};
 
 
 	class
 	class
@@ -97,17 +89,6 @@ private:
 		ShaderProgramPtr m_grProg;
 		ShaderProgramPtr m_grProg;
 	} m_irradiance; ///< Irradiance.
 	} m_irradiance; ///< Irradiance.
 
 
-	class
-	{
-	public:
-		ShaderProgramResourcePtr m_prog;
-		DynamicArray<ShaderProgramPtr> m_grProgs; ///< One program for a number of probe counts.
-		Array<UVec3, GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT> m_volumeSizes; ///< This is dynamic.
-		Array<F32, GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT> m_cellSizes;
-		Array<U8, 3> m_workgroupSize = {{8, 8, 8}};
-		Array<F32, GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT - 1> m_levelMaxDistances;
-	} m_clipmap; ///< Clipmap population.
-
 	InternalContext* m_giCtx = nullptr;
 	InternalContext* m_giCtx = nullptr;
 	DynamicArray<CacheEntry> m_cacheEntries;
 	DynamicArray<CacheEntry> m_cacheEntries;
 	HashMap<U64, U32> m_probeUuidToCacheEntryIdx;
 	HashMap<U64, U32> m_probeUuidToCacheEntryIdx;
@@ -119,19 +100,13 @@ private:
 	ANKI_USE_RESULT Error initShadowMapping(const ConfigSet& cfg);
 	ANKI_USE_RESULT Error initShadowMapping(const ConfigSet& cfg);
 	ANKI_USE_RESULT Error initLightShading(const ConfigSet& cfg);
 	ANKI_USE_RESULT Error initLightShading(const ConfigSet& cfg);
 	ANKI_USE_RESULT Error initIrradiance(const ConfigSet& cfg);
 	ANKI_USE_RESULT Error initIrradiance(const ConfigSet& cfg);
-	ANKI_USE_RESULT Error initClipmap(const ConfigSet& cfg);
-
-	void populateRenderGraphClipmap(InternalContext& ctx);
 
 
 	void runGBufferInThread(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx) const;
 	void runGBufferInThread(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx) const;
 	void runShadowmappingInThread(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx) const;
 	void runShadowmappingInThread(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx) const;
 	void runLightShading(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx);
 	void runLightShading(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx);
 	void runIrradiance(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx);
 	void runIrradiance(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx);
-	void runClipmapPopulation(RenderPassWorkContext& rgraphCtx, InternalContext& giCtx);
 
 
-	void prepareProbes(RenderingContext& rctx,
-		GlobalIlluminationProbeQueueElement*& probeToUpdateThisFrame,
-		UVec3& probeToUpdateThisFrameCell);
+	void prepareProbes(InternalContext& giCtx);
 };
 };
 /// @}
 /// @}
 
 

+ 23 - 21
src/anki/renderer/LightShading.cpp

@@ -120,27 +120,32 @@ void LightShading::run(RenderPassWorkContext& rgraphCtx)
 		rgraphCtx.bindColorTexture(0, 6, m_r->getIndirect().getIrradianceRt());
 		rgraphCtx.bindColorTexture(0, 6, m_r->getIndirect().getIrradianceRt());
 		cmdb->bindTexture(0, 7, m_r->getIndirect().getIntegrationLut(), TextureUsageBit::SAMPLED_FRAGMENT);
 		cmdb->bindTexture(0, 7, m_r->getIndirect().getIntegrationLut(), TextureUsageBit::SAMPLED_FRAGMENT);
 
 
-		bindStorage(cmdb, 0, 8, rsrc.m_clustersToken);
-		bindStorage(cmdb, 0, 9, rsrc.m_indicesToken);
-
-		const auto& arr = m_r->getGlobalIllumination().getClipmapVolumeRenderTargets();
-		for(U level = 0; level < GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT; ++level)
+		for(U idx = 0; idx < MAX_VISIBLE_GLOBAL_ILLUMINATION_PROBES; ++idx)
 		{
 		{
-			for(U dir = 0; dir < 6; ++dir)
+			if(idx < ctx.m_renderQueue->m_giProbes.getSize())
+			{
+				rgraphCtx.bindColorTexture(
+					0, 8, m_r->getGlobalIllumination().getVolumeRenderTarget(ctx.m_renderQueue->m_giProbes[idx]), idx);
+			}
+			else
 			{
 			{
-				rgraphCtx.bindColorTexture(0, 10, arr[level][dir], level * 6 + dir);
+				cmdb->bindTexture(0, 8, m_r->getDummyTextureView3d(), TextureUsageBit::SAMPLED_FRAGMENT, idx);
 			}
 			}
 		}
 		}
+		bindUniforms(cmdb, 0, 9, rsrc.m_globalIlluminationProbesToken);
 
 
-		cmdb->bindSampler(0, 11, m_r->getSamplers().m_nearestNearestClamp);
-		cmdb->bindSampler(0, 12, m_r->getSamplers().m_trilinearRepeat);
-		rgraphCtx.bindColorTexture(0, 13, m_r->getGBuffer().getColorRt(0));
-		rgraphCtx.bindColorTexture(0, 14, m_r->getGBuffer().getColorRt(1));
-		rgraphCtx.bindColorTexture(0, 15, m_r->getGBuffer().getColorRt(2));
+		bindStorage(cmdb, 0, 10, rsrc.m_clustersToken);
+		bindStorage(cmdb, 0, 11, rsrc.m_indicesToken);
+
+		cmdb->bindSampler(0, 12, m_r->getSamplers().m_nearestNearestClamp);
+		cmdb->bindSampler(0, 13, m_r->getSamplers().m_trilinearRepeat);
+		rgraphCtx.bindColorTexture(0, 14, m_r->getGBuffer().getColorRt(0));
+		rgraphCtx.bindColorTexture(0, 15, m_r->getGBuffer().getColorRt(1));
+		rgraphCtx.bindColorTexture(0, 16, m_r->getGBuffer().getColorRt(2));
 		rgraphCtx.bindTexture(
 		rgraphCtx.bindTexture(
-			0, 16, m_r->getGBuffer().getDepthRt(), TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
-		rgraphCtx.bindColorTexture(0, 17, m_r->getSsr().getRt());
-		rgraphCtx.bindColorTexture(0, 18, m_r->getSsao().getRt());
+			0, 17, m_r->getGBuffer().getDepthRt(), TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
+		rgraphCtx.bindColorTexture(0, 18, m_r->getSsr().getRt());
+		rgraphCtx.bindColorTexture(0, 19, m_r->getSsao().getRt());
 
 
 		// Draw
 		// Draw
 		drawQuad(cmdb);
 		drawQuad(cmdb);
@@ -215,13 +220,10 @@ void LightShading::populateRenderGraph(RenderingContext& ctx)
 	pass.newDependency({m_r->getIndirect().getReflectionRt(), TextureUsageBit::SAMPLED_FRAGMENT});
 	pass.newDependency({m_r->getIndirect().getReflectionRt(), TextureUsageBit::SAMPLED_FRAGMENT});
 	pass.newDependency({m_r->getIndirect().getIrradianceRt(), TextureUsageBit::SAMPLED_FRAGMENT});
 	pass.newDependency({m_r->getIndirect().getIrradianceRt(), TextureUsageBit::SAMPLED_FRAGMENT});
 
 
-	const auto& arr = m_r->getGlobalIllumination().getClipmapVolumeRenderTargets();
-	for(U level = 0; level < GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT; ++level)
+	for(U idx = 0; idx < ctx.m_renderQueue->m_giProbes.getSize(); ++idx)
 	{
 	{
-		for(U dir = 0; dir < 6; ++dir)
-		{
-			pass.newDependency({arr[level][dir], TextureUsageBit::SAMPLED_FRAGMENT});
-		}
+		pass.newDependency({m_r->getGlobalIllumination().getVolumeRenderTarget(ctx.m_renderQueue->m_giProbes[idx]),
+			TextureUsageBit::SAMPLED_FRAGMENT});
 	}
 	}
 
 
 	// Fog
 	// Fog

+ 1 - 2
src/anki/renderer/RenderQueue.h

@@ -186,8 +186,7 @@ public:
 	Vec3 m_aabbMax;
 	Vec3 m_aabbMax;
 	UVec3 m_cellCounts;
 	UVec3 m_cellCounts;
 	U32 m_totalCellCount;
 	U32 m_totalCellCount;
-	F32 m_cellSize;
-	U32 m_cacheEntryIndex; ///< Renderer internal.
+	Vec3 m_cellSizes; ///< The cells might not be cubes.
 
 
 	GlobalIlluminationProbeQueueElement()
 	GlobalIlluminationProbeQueueElement()
 	{
 	{

+ 0 - 8
src/anki/renderer/Renderer.cpp

@@ -600,14 +600,6 @@ void Renderer::updateLightShadingUniforms(RenderingContext& ctx) const
 	{
 	{
 		blk->m_dirLight.m_active = 0;
 		blk->m_dirLight.m_active = 0;
 	}
 	}
-
-	// GI clipmap
-	for(U level = 0; level < GLOBAL_ILLUMINATION_CLIPMAP_LEVEL_COUNT; ++level)
-	{
-		const Aabb& box = m_gi->getClipmapAabb(level);
-		blk->m_globalIlluminationClipmapLevels[level].m_min = box.getMin().xyz();
-		blk->m_globalIlluminationClipmapLevels[level].m_max = box.getMax().xyz();
-	}
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 4 - 8
src/anki/scene/components/GlobalIlluminationProbeComponent.h

@@ -88,8 +88,7 @@ public:
 		el.m_aabbMax = m_aabbMax;
 		el.m_aabbMax = m_aabbMax;
 		el.m_cellCounts = m_cellCounts;
 		el.m_cellCounts = m_cellCounts;
 		el.m_totalCellCount = m_cellCounts.x() * m_cellCounts.y() * m_cellCounts.z();
 		el.m_totalCellCount = m_cellCounts.x() * m_cellCounts.y() * m_cellCounts.z();
-		el.m_cellSize = m_cellSize;
-		ANKI_DEBUG_CODE(el.m_cacheEntryIndex = MAX_U32);
+		el.m_cellSizes = (m_aabbMax - m_aabbMin) / Vec3(m_cellCounts);
 	}
 	}
 
 
 	ANKI_USE_RESULT Error update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated) override
 	ANKI_USE_RESULT Error update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated) override
@@ -132,14 +131,11 @@ private:
 	{
 	{
 		for(U i = 0; i < 3; ++i)
 		for(U i = 0; i < 3; ++i)
 		{
 		{
-			// Align the box
-			alignRoundDown(m_cellSize, m_aabbMin[i]);
-			alignRoundUp(m_cellSize, m_aabbMax[i]);
 			ANKI_ASSERT(m_aabbMax[i] > m_aabbMin[i]);
 			ANKI_ASSERT(m_aabbMax[i] > m_aabbMin[i]);
 
 
-			// Compute the counts
-			const F32 epsilon = m_cellSize / 100.0f;
-			m_cellCounts[i] = U32((m_aabbMax[i] - m_aabbMin[i] + epsilon) / m_cellSize);
+			const F32 dist = m_aabbMax[i] - m_aabbMin[i];
+			m_cellCounts[i] = U32(ceil(dist / m_cellSize));
+			ANKI_ASSERT(m_cellCounts[i] > 0);
 		}
 		}
 	}
 	}
 };
 };