浏览代码

Improve vol fog. Add 2nd bounce on indirect

Panagiotis Christopoulos Charitos 7 年之前
父节点
当前提交
1e31e7f7b2

+ 1 - 1
sandbox/Main.cpp

@@ -46,7 +46,7 @@ Error MyApp::init(int argc, char* argv[])
 	ResourceManager& resources = getResourceManager();
 
 	renderer.getOffscreenRenderer().getVolumetricFog().setFogParticleColor(Vec3(1.0, 0.9, 0.9));
-	renderer.getOffscreenRenderer().getVolumetricFog().setParticleDensity(0.25f);
+	renderer.getOffscreenRenderer().getVolumetricFog().setParticleDensity(1.0f);
 
 	if(getenv("PROFILE"))
 	{

+ 1 - 1
shaders/VolumetricFogAccumulation.glslp

@@ -75,4 +75,4 @@ void main()
 	}
 }
 
-#pragma anki end
+#pragma anki end

+ 18 - 8
shaders/VolumetricLightingAccumulation.glslp

@@ -19,6 +19,8 @@
 // Lower the ESM constant to smooth the shadows
 #define ESM_CONSTANT 30.0
 
+const F32 PHASE_FUNCTION_ANISOTROPY = 0.3;
+
 layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = WORKGROUP_SIZE.z) in;
 
 layout(ANKI_IMAGE_BINDING(0, 0)) writeonly uniform image3D u_volume;
@@ -75,17 +77,17 @@ Vec3 worldPosInsideCluster(Vec3 relativePos)
 	return worldPos;
 }
 
+// https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter16.html
 F32 phaseFunction(Vec3 viewDir, Vec3 lightDir, F32 g)
 {
 	F32 g2 = g * g;
+	F32 cosTheta = max(0.0, dot(viewDir, lightDir));
+	F32 cosTheta2 = cosTheta * cosTheta;
 
 	F32 a = (3.0 * (1.0 - g2)) / (2.0 * (2.0 + g2));
-
-	F32 cosTheta = dot(viewDir, lightDir);
-	F32 cosTheta2 = cosTheta * cosTheta;
 	F32 b = (1.0 + cosTheta2) / pow(1.0 + g2 - 2.0 * g * cosTheta, 3.0 / 2.0);
 
-	return a / b;
+	return saturate(a * b);
 }
 
 Vec3 accumulateLights(U32 clusterIdx, Vec3 worldPos)
@@ -110,6 +112,8 @@ Vec3 accumulateLights(U32 clusterIdx, Vec3 worldPos)
 		Vec3 frag2Light = light.m_posRadius.xyz - worldPos;
 		F32 factor = computeAttenuationFactor(light.m_posRadius.w, frag2Light);
 
+		factor *= phaseFunction(viewDir, normalize(worldPos - light.m_posRadius.xyz), PHASE_FUNCTION_ANISOTROPY);
+
 #if ENABLE_SHADOWS
 		if(light.m_diffuseColorTileSize.w >= 0.0)
 		{
@@ -136,6 +140,8 @@ Vec3 accumulateLights(U32 clusterIdx, Vec3 worldPos)
 		factor *=
 			computeSpotFactor(l, light.m_outerCosInnerCos.x, light.m_outerCosInnerCos.y, light.m_lightDirRadius.xyz);
 
+		factor *= phaseFunction(viewDir, light.m_lightDirRadius.xyz, PHASE_FUNCTION_ANISOTROPY);
+
 #if ENABLE_SHADOWS
 		F32 shadowmapLayerIdx = light.m_diffuseColorShadowmapId.w;
 		if(shadowmapLayerIdx >= 0.0)
@@ -206,14 +212,18 @@ void main()
 		k /= F32(FINAL_CLUSTER_Z + 1u);
 
 		// Read prev
-		Vec3 prev = textureLod(u_prevVolume, Vec3(prevUv, k), 0.0).rgb;
+		Vec3 uvw = Vec3(prevUv, k);
+		if(all(lessThan(abs(uvw), Vec3(1.0))))
+		{
+			Vec3 prev = textureLod(u_prevVolume, uvw, 0.0).rgb;
 
-		// Modulate
-		color = mix(prev, color, 1.0 / 16.0);
+			// Modulate
+			color = mix(prev, color, 1.0 / 16.0);
+		}
 	}
 
 	// Write result
 	imageStore(u_volume, IVec3(gl_GlobalInvocationID), Vec4(color, 0.0));
 }
 
-#pragma anki end
+#pragma anki end

+ 12 - 0
src/anki/gr/Enums.h

@@ -425,6 +425,18 @@ enum class SamplingFilter : U8
 	BASE ///< Only for mipmaps
 };
 
+enum class SamplingAddressing : U8
+{
+	CLAMP,
+	REPEAT,
+	BLACK,
+	WHITE,
+
+	COUNT,
+	FIRST = 0,
+	LAST = COUNT - 1,
+};
+
 enum class ShaderType : U8
 {
 	VERTEX,

+ 5 - 5
src/anki/gr/Sampler.h

@@ -23,7 +23,7 @@ public:
 	SamplingFilter m_mipmapFilter = SamplingFilter::BASE;
 	CompareOperation m_compareOperation = CompareOperation::ALWAYS;
 	I8 m_anisotropyLevel = 0;
-	Bool8 m_repeat = true; ///< Repeat or clamp.
+	SamplingAddressing m_addressing = SamplingAddressing::REPEAT;
 	U8 _m_padding[3] = {0, 0, 0};
 
 	SamplerInitInfo() = default;
@@ -36,11 +36,11 @@ public:
 	U64 computeHash() const
 	{
 		const U8* const first = reinterpret_cast<const U8* const>(&m_minLod);
-		const U8* const last = reinterpret_cast<const U8* const>(&m_repeat) + sizeof(m_repeat);
+		const U8* const last = reinterpret_cast<const U8* const>(&m_addressing) + sizeof(m_addressing);
 		const U size = last - first;
-		ANKI_ASSERT(
-			size
-			== sizeof(F32) * 2 + sizeof(SamplingFilter) * 2 + sizeof(CompareOperation) + sizeof(I8) + sizeof(Bool8));
+		ANKI_ASSERT(size
+					== sizeof(F32) * 2 + sizeof(SamplingFilter) * 2 + sizeof(CompareOperation) + sizeof(I8)
+						   + sizeof(SamplerInitInfo));
 		return anki::computeHash(first, size);
 	}
 };

+ 16 - 5
src/anki/gr/vulkan/SamplerFactory.cpp

@@ -42,13 +42,24 @@ Error MicroSampler::init(const SamplerInitInfo& inf)
 		ci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
 	}
 
-	if(inf.m_repeat)
-	{
-		ci.addressModeU = ci.addressModeV = ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
-	}
-	else
+	switch(inf.m_addressing)
 	{
+	case SamplingAddressing::CLAMP:
 		ci.addressModeU = ci.addressModeV = ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+		break;
+	case SamplingAddressing::REPEAT:
+		ci.addressModeU = ci.addressModeV = ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
+		break;
+	case SamplingAddressing::BLACK:
+		ci.addressModeU = ci.addressModeV = ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
+		ci.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+		break;
+	case SamplingAddressing::WHITE:
+		ci.addressModeU = ci.addressModeV = ci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
+		ci.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
+		break;
+	default:
+		ANKI_ASSERT(0);
 	}
 
 	ci.mipLodBias = 0.0;

+ 176 - 150
src/anki/renderer/Indirect.cpp

@@ -59,7 +59,7 @@ Error Indirect::initInternal(const ConfigSet& config)
 	sinit.m_mipmapFilter = SamplingFilter::BASE;
 	sinit.m_minLod = 0.0;
 	sinit.m_maxLod = 1.0;
-	sinit.m_repeat = false;
+	sinit.m_addressing = SamplingAddressing::CLAMP;
 	m_integrationLutSampler = getGrManager().newSampler(sinit);
 
 	return Error::NONE;
@@ -492,191 +492,217 @@ void Indirect::populateRenderGraph(RenderingContext& rctx)
 	prepareProbes(rctx, probeToUpdate, probeToUpdateCacheEntryIdx);
 
 	// Render a probe if needed
-	if(probeToUpdate)
+	if(!probeToUpdate)
 	{
-		m_ctx.m_cacheEntryIdx = probeToUpdateCacheEntryIdx;
-		m_ctx.m_probe = probeToUpdate;
+		// Just import and exit
 
-		if(!m_cacheEntries[probeToUpdateCacheEntryIdx].m_lightShadingFbDescrs[0].isBacked())
+		m_ctx.m_lightShadingRt = rgraph.importRenderTarget(m_lightShading.m_cubeArr, TextureUsageBit::SAMPLED_FRAGMENT);
+		m_ctx.m_irradianceRt = rgraph.importRenderTarget(m_irradiance.m_cubeArr, TextureUsageBit::SAMPLED_FRAGMENT);
+
+		return;
+	}
+
+	m_ctx.m_cacheEntryIdx = probeToUpdateCacheEntryIdx;
+	m_ctx.m_probe = probeToUpdate;
+
+	if(!m_cacheEntries[probeToUpdateCacheEntryIdx].m_lightShadingFbDescrs[0].isBacked())
+	{
+		initCacheEntry(probeToUpdateCacheEntryIdx);
+	}
+
+	// G-buffer pass
+	{
+		// RTs
+		Array<RenderTargetHandle, MAX_COLOR_ATTACHMENTS> rts;
+		for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
 		{
-			initCacheEntry(probeToUpdateCacheEntryIdx);
+			m_ctx.m_gbufferColorRts[i] = rgraph.newRenderTarget(m_gbuffer.m_colorRtDescrs[i]);
+			rts[i] = m_ctx.m_gbufferColorRts[i];
 		}
+		m_ctx.m_gbufferDepthRt = rgraph.newRenderTarget(m_gbuffer.m_depthRtDescr);
 
-		// G-buffer pass
-		{
-			// RTs
-			Array<RenderTargetHandle, MAX_COLOR_ATTACHMENTS> rts;
-			for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
-			{
-				m_ctx.m_gbufferColorRts[i] = rgraph.newRenderTarget(m_gbuffer.m_colorRtDescrs[i]);
-				rts[i] = m_ctx.m_gbufferColorRts[i];
-			}
-			m_ctx.m_gbufferDepthRt = rgraph.newRenderTarget(m_gbuffer.m_depthRtDescr);
+		// Pass
+		GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI gbuff");
+		pass.setFramebufferInfo(m_gbuffer.m_fbDescr, rts, m_ctx.m_gbufferDepthRt);
+		pass.setWork(runGBufferCallback, this, 0);
 
-			// Pass
-			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI gbuff");
-			pass.setFramebufferInfo(m_gbuffer.m_fbDescr, rts, m_ctx.m_gbufferDepthRt);
-			pass.setWork(runGBufferCallback, this, 0);
+		for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
+		{
+			pass.newDependency({m_ctx.m_gbufferColorRts[i], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
+		}
 
-			for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
-			{
-				pass.newDependency({m_ctx.m_gbufferColorRts[i], TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE});
-			}
+		TextureSubresourceInfo subresource(DepthStencilAspectBit::DEPTH);
+		pass.newDependency({m_ctx.m_gbufferDepthRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE, subresource});
+	}
 
-			TextureSubresourceInfo subresource(DepthStencilAspectBit::DEPTH);
-			pass.newDependency(
-				{m_ctx.m_gbufferDepthRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE, subresource});
-		}
+	// Light shading passes
+	{
+		Array<RenderPassWorkCallback, 6> callbacks = {{runLightShadingCallback<0>,
+			runLightShadingCallback<1>,
+			runLightShadingCallback<2>,
+			runLightShadingCallback<3>,
+			runLightShadingCallback<4>,
+			runLightShadingCallback<5>}};
+
+		// RT
+		m_ctx.m_lightShadingRt = rgraph.importRenderTarget(m_lightShading.m_cubeArr, TextureUsageBit::SAMPLED_FRAGMENT);
 
-		// Light shading passes
+		// Passes
+		static const Array<CString, 6> passNames = {{"GI LightShad #0",
+			"GI LightShad #1",
+			"GI LightShad #2",
+			"GI LightShad #3",
+			"GI LightShad #4",
+			"GI LightShad #5"}};
+		for(U faceIdx = 0; faceIdx < 6; ++faceIdx)
 		{
-			Array<RenderPassWorkCallback, 6> callbacks = {{runLightShadingCallback<0>,
-				runLightShadingCallback<1>,
-				runLightShadingCallback<2>,
-				runLightShadingCallback<3>,
-				runLightShadingCallback<4>,
-				runLightShadingCallback<5>}};
-
-			// RT
-			m_ctx.m_lightShadingRt =
-				rgraph.importRenderTarget(m_lightShading.m_cubeArr, TextureUsageBit::SAMPLED_FRAGMENT);
-
-			// Passes
-			static const Array<CString, 6> passNames = {{"GI LightShad #0",
-				"GI LightShad #1",
-				"GI LightShad #2",
-				"GI LightShad #3",
-				"GI LightShad #4",
-				"GI LightShad #5"}};
-			for(U faceIdx = 0; faceIdx < 6; ++faceIdx)
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
+			pass.setFramebufferInfo(m_cacheEntries[probeToUpdateCacheEntryIdx].m_lightShadingFbDescrs[faceIdx],
+				{{m_ctx.m_lightShadingRt}},
+				{});
+			pass.setWork(callbacks[faceIdx], this, 0);
+
+			TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
+			pass.newDependency({m_ctx.m_lightShadingRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, subresource});
+
+			for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
 			{
-				GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
-				pass.setFramebufferInfo(m_cacheEntries[probeToUpdateCacheEntryIdx].m_lightShadingFbDescrs[faceIdx],
-					{{m_ctx.m_lightShadingRt}},
-					{});
-				pass.setWork(callbacks[faceIdx], this, 0);
-
-				TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
-				pass.newDependency(
-					{m_ctx.m_lightShadingRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, subresource});
-
-				for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
-				{
-					pass.newDependency({m_ctx.m_gbufferColorRts[i], TextureUsageBit::SAMPLED_FRAGMENT});
-				}
-				pass.newDependency({m_ctx.m_gbufferDepthRt,
-					TextureUsageBit::SAMPLED_FRAGMENT,
-					TextureSubresourceInfo(DepthStencilAspectBit::DEPTH)});
+				pass.newDependency({m_ctx.m_gbufferColorRts[i], TextureUsageBit::SAMPLED_FRAGMENT});
 			}
+			pass.newDependency({m_ctx.m_gbufferDepthRt,
+				TextureUsageBit::SAMPLED_FRAGMENT,
+				TextureSubresourceInfo(DepthStencilAspectBit::DEPTH)});
 		}
+	}
 
-		// Irradiance passes
+	// Irradiance passes
+	{
+		static const Array<RenderPassWorkCallback, 6> callbacks = {{runIrradianceCallback<0>,
+			runIrradianceCallback<1>,
+			runIrradianceCallback<2>,
+			runIrradianceCallback<3>,
+			runIrradianceCallback<4>,
+			runIrradianceCallback<5>}};
+
+		// Rt
+		m_ctx.m_irradianceRt = rgraph.importRenderTarget(m_irradiance.m_cubeArr, TextureUsageBit::SAMPLED_FRAGMENT);
+
+		static const Array<CString, 6> passNames = {
+			{"GI Irr/ce #0", "GI Irr/ce #1", "GI Irr/ce #2", "GI Irr/ce #3", "GI Irr/ce #4", "GI Irr/ce #5"}};
+		for(U faceIdx = 0; faceIdx < 6; ++faceIdx)
 		{
-			static const Array<RenderPassWorkCallback, 6> callbacks = {{runIrradianceCallback<0>,
-				runIrradianceCallback<1>,
-				runIrradianceCallback<2>,
-				runIrradianceCallback<3>,
-				runIrradianceCallback<4>,
-				runIrradianceCallback<5>}};
-
-			// Rt
-			m_ctx.m_irradianceRt = rgraph.importRenderTarget(m_irradiance.m_cubeArr, TextureUsageBit::SAMPLED_FRAGMENT);
-
-			static const Array<CString, 6> passNames = {
-				{"GI Irr/ce #0", "GI Irr/ce #1", "GI Irr/ce #2", "GI Irr/ce #3", "GI Irr/ce #4", "GI Irr/ce #5"}};
-			for(U faceIdx = 0; faceIdx < 6; ++faceIdx)
-			{
-				GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
 
-				pass.setFramebufferInfo(m_cacheEntries[probeToUpdateCacheEntryIdx].m_irradianceFbDescrs[faceIdx],
-					{{m_ctx.m_irradianceRt}},
-					{});
+			pass.setFramebufferInfo(
+				m_cacheEntries[probeToUpdateCacheEntryIdx].m_irradianceFbDescrs[faceIdx], {{m_ctx.m_irradianceRt}}, {});
 
-				pass.setWork(callbacks[faceIdx], this, 0);
+			pass.setWork(callbacks[faceIdx], this, 0);
 
-				// Read a cube but only one layer and level
-				TextureSubresourceInfo readSubresource;
-				readSubresource.m_faceCount = 6;
-				readSubresource.m_firstLayer = probeToUpdateCacheEntryIdx;
-				pass.newDependency({m_ctx.m_lightShadingRt, TextureUsageBit::SAMPLED_FRAGMENT, readSubresource});
+			// Read a cube but only one layer and level
+			TextureSubresourceInfo readSubresource;
+			readSubresource.m_faceCount = 6;
+			readSubresource.m_firstLayer = probeToUpdateCacheEntryIdx;
+			pass.newDependency({m_ctx.m_lightShadingRt, TextureUsageBit::SAMPLED_FRAGMENT, readSubresource});
 
-				TextureSubresourceInfo writeSubresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
-				pass.newDependency(
-					{m_ctx.m_irradianceRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, writeSubresource});
-			}
+			TextureSubresourceInfo writeSubresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
+			pass.newDependency({m_ctx.m_irradianceRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, writeSubresource});
 		}
+	}
 
-		// Write irradiance back to refl
+	// Write irradiance back to refl
+	{
+		static const Array<RenderPassWorkCallback, 6> callbacks = {{runIrradianceToReflCallback<0>,
+			runIrradianceToReflCallback<1>,
+			runIrradianceToReflCallback<2>,
+			runIrradianceToReflCallback<3>,
+			runIrradianceToReflCallback<4>,
+			runIrradianceToReflCallback<5>}};
+
+		// Rt
+		static const Array<CString, 6> passNames = {{"GI Irr2Refl #0",
+			"GI Irr2Refl #1",
+			"GI Irr2Refl #2",
+			"GI Irr2Refl #3",
+			"GI Irr2Refl #4",
+			"GI Irr2Refl #5"}};
+		for(U faceIdx = 0; faceIdx < 6; ++faceIdx)
 		{
-			static const Array<RenderPassWorkCallback, 6> callbacks = {{runIrradianceToReflCallback<0>,
-				runIrradianceToReflCallback<1>,
-				runIrradianceToReflCallback<2>,
-				runIrradianceToReflCallback<3>,
-				runIrradianceToReflCallback<4>,
-				runIrradianceToReflCallback<5>}};
-
-			// Rt
-			static const Array<CString, 6> passNames = {{"GI Irr2Refl #0",
-				"GI Irr2Refl #1",
-				"GI Irr2Refl #2",
-				"GI Irr2Refl #3",
-				"GI Irr2Refl #4",
-				"GI Irr2Refl #5"}};
-			for(U faceIdx = 0; faceIdx < 6; ++faceIdx)
-			{
-				GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
 
-				pass.setFramebufferInfo(m_cacheEntries[probeToUpdateCacheEntryIdx].m_irradianceToReflFbDescrs[faceIdx],
-					{{m_ctx.m_lightShadingRt}},
-					{});
+			pass.setFramebufferInfo(m_cacheEntries[probeToUpdateCacheEntryIdx].m_irradianceToReflFbDescrs[faceIdx],
+				{{m_ctx.m_lightShadingRt}},
+				{});
 
-				pass.setWork(callbacks[faceIdx], this, 0);
+			pass.setWork(callbacks[faceIdx], this, 0);
 
-				for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
-				{
-					pass.newDependency({m_ctx.m_gbufferColorRts[i], TextureUsageBit::SAMPLED_FRAGMENT});
-				}
+			for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
+			{
+				pass.newDependency({m_ctx.m_gbufferColorRts[i], TextureUsageBit::SAMPLED_FRAGMENT});
+			}
 
-				TextureSubresourceInfo readSubresource;
-				readSubresource.m_faceCount = 6;
-				readSubresource.m_firstLayer = probeToUpdateCacheEntryIdx;
-				pass.newDependency({m_ctx.m_irradianceRt, TextureUsageBit::SAMPLED_FRAGMENT, readSubresource});
+			TextureSubresourceInfo readSubresource;
+			readSubresource.m_faceCount = 6;
+			readSubresource.m_firstLayer = probeToUpdateCacheEntryIdx;
+			pass.newDependency({m_ctx.m_irradianceRt, TextureUsageBit::SAMPLED_FRAGMENT, readSubresource});
 
-				TextureSubresourceInfo writeSubresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
-				pass.newDependency(
-					{m_ctx.m_lightShadingRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE, writeSubresource});
-			}
+			TextureSubresourceInfo writeSubresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
+			pass.newDependency(
+				{m_ctx.m_lightShadingRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE, writeSubresource});
 		}
+	}
 
-		// Mipmapping "passes"
+	// Irradiance passes 2nd bounce
+	{
+		static const Array<RenderPassWorkCallback, 6> callbacks = {{runIrradianceCallback<0>,
+			runIrradianceCallback<1>,
+			runIrradianceCallback<2>,
+			runIrradianceCallback<3>,
+			runIrradianceCallback<4>,
+			runIrradianceCallback<5>}};
+
+		static const Array<CString, 6> passNames = {
+			{"GI Irr 2nd #0", "GI Irr 2nd #1", "GI Irr 2nd #2", "GI Irr 2nd #3", "GI Irr 2nd #4", "GI Irr 2nd #5"}};
+		for(U faceIdx = 0; faceIdx < 6; ++faceIdx)
 		{
-			static const Array<RenderPassWorkCallback, 6> callbacks = {{runMipmappingOfLightShadingCallback<0>,
-				runMipmappingOfLightShadingCallback<1>,
-				runMipmappingOfLightShadingCallback<2>,
-				runMipmappingOfLightShadingCallback<3>,
-				runMipmappingOfLightShadingCallback<4>,
-				runMipmappingOfLightShadingCallback<5>}};
-
-			static const Array<CString, 6> passNames = {
-				{"GI Mip #0", "GI Mip #1", "GI Mip #2", "GI Mip #3", "GI Mip #4", "GI Mip #5"}};
-			for(U faceIdx = 0; faceIdx < 6; ++faceIdx)
-			{
-				GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
-				pass.setWork(callbacks[faceIdx], this, 0);
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
 
-				TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
-				subresource.m_mipmapCount = m_lightShading.m_mipCount;
+			pass.setFramebufferInfo(
+				m_cacheEntries[probeToUpdateCacheEntryIdx].m_irradianceFbDescrs[faceIdx], {{m_ctx.m_irradianceRt}}, {});
 
-				pass.newDependency({m_ctx.m_lightShadingRt, TextureUsageBit::GENERATE_MIPMAPS, subresource});
-			}
+			pass.setWork(callbacks[faceIdx], this, 0);
+
+			// Read a cube but only one layer and level
+			TextureSubresourceInfo readSubresource;
+			readSubresource.m_faceCount = 6;
+			readSubresource.m_firstLayer = probeToUpdateCacheEntryIdx;
+			pass.newDependency({m_ctx.m_lightShadingRt, TextureUsageBit::SAMPLED_FRAGMENT, readSubresource});
+
+			TextureSubresourceInfo writeSubresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
+			pass.newDependency({m_ctx.m_irradianceRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, writeSubresource});
 		}
 	}
-	else
+
+	// Mipmapping "passes"
 	{
-		// Just import
+		static const Array<RenderPassWorkCallback, 6> callbacks = {{runMipmappingOfLightShadingCallback<0>,
+			runMipmappingOfLightShadingCallback<1>,
+			runMipmappingOfLightShadingCallback<2>,
+			runMipmappingOfLightShadingCallback<3>,
+			runMipmappingOfLightShadingCallback<4>,
+			runMipmappingOfLightShadingCallback<5>}};
+
+		static const Array<CString, 6> passNames = {
+			{"GI Mip #0", "GI Mip #1", "GI Mip #2", "GI Mip #3", "GI Mip #4", "GI Mip #5"}};
+		for(U faceIdx = 0; faceIdx < 6; ++faceIdx)
+		{
+			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
+			pass.setWork(callbacks[faceIdx], this, 0);
 
-		m_ctx.m_lightShadingRt = rgraph.importRenderTarget(m_lightShading.m_cubeArr, TextureUsageBit::SAMPLED_FRAGMENT);
-		m_ctx.m_irradianceRt = rgraph.importRenderTarget(m_irradiance.m_cubeArr, TextureUsageBit::SAMPLED_FRAGMENT);
+			TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
+			subresource.m_mipmapCount = m_lightShading.m_mipCount;
+
+			pass.newDependency({m_ctx.m_lightShadingRt, TextureUsageBit::GENERATE_MIPMAPS, subresource});
+		}
 	}
 }
 

+ 2 - 2
src/anki/renderer/Renderer.cpp

@@ -172,7 +172,7 @@ Error Renderer::initInternal(const ConfigSet& config)
 	ANKI_CHECK(m_uiStage->init(config));
 
 	SamplerInitInfo sinit("Renderer");
-	sinit.m_repeat = false;
+	sinit.m_addressing = SamplingAddressing::CLAMP;
 	sinit.m_mipmapFilter = SamplingFilter::BASE;
 	sinit.m_minMagFilter = SamplingFilter::NEAREST;
 	m_nearestSampler = m_gr->newSampler(sinit);
@@ -181,7 +181,7 @@ Error Renderer::initInternal(const ConfigSet& config)
 	m_linearSampler = m_gr->newSampler(sinit);
 
 	sinit.m_mipmapFilter = SamplingFilter::LINEAR;
-	sinit.m_repeat = true;
+	sinit.m_addressing = SamplingAddressing::REPEAT;
 	m_trilinearRepeatSampler = m_gr->newSampler(sinit);
 
 	sinit.m_mipmapFilter = SamplingFilter::NEAREST;

+ 1 - 1
src/anki/resource/TextureResource.cpp

@@ -185,7 +185,7 @@ Error TextureResource::load(const ResourceFilename& filename, Bool async)
 	SamplerInitInfo samplerInit("TextureRsrc");
 	samplerInit.m_minMagFilter = SamplingFilter::LINEAR;
 	samplerInit.m_mipmapFilter = SamplingFilter::LINEAR;
-	samplerInit.m_repeat = true;
+	samplerInit.m_addressing = SamplingAddressing::REPEAT;
 	samplerInit.m_anisotropyLevel = getManager().getTextureAnisotropy();
 	m_sampler = getManager().getGrManager().newSampler(samplerInit);
 

+ 1 - 1
src/anki/ui/Canvas.cpp

@@ -58,7 +58,7 @@ Error Canvas::init(FontPtr font, U32 fontHeight, U32 width, U32 height)
 	SamplerInitInfo samplerInit("Canvas");
 	samplerInit.m_minMagFilter = SamplingFilter::LINEAR;
 	samplerInit.m_mipmapFilter = SamplingFilter::LINEAR;
-	samplerInit.m_repeat = true;
+	samplerInit.m_addressing = SamplingAddressing::REPEAT;
 	m_sampler = m_manager->getGrManager().newSampler(samplerInit);
 
 	return Error::NONE;