瀏覽代碼

Apply the indirect diffuse back to the reflection cubemap

Panagiotis Christopoulos Charitos 7 年之前
父節點
當前提交
37c11fb0a1

+ 54 - 0
shaders/ApplyIrradianceToReflection.ankiprog

@@ -0,0 +1,54 @@
+<!-- 
+Copyright (C) 2009-2018, Panagiotis Christopoulos Charitos and contributors.
+All rights reserved.
+Code licensed under the BSD License.
+http://www.anki3d.org/LICENSE
+-->
+<shaderProgram>
+	<shaders>
+		<shader type="vert">
+			<source><![CDATA[
+#include <shaders/QuadVert.glsl>
+			]]></source>
+		</shader>
+
+		<shader type="frag">
+			<source><![CDATA[
+#include <shaders/Pack.glsl>
+
+layout(location = 0) in Vec2 in_uv;
+
+layout(location = 0) out Vec3 out_color;
+
+layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_gbufferTex0;
+layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2D u_gbufferTex1;
+layout(ANKI_TEX_BINDING(0, 2)) uniform sampler2D u_gbufferTex2;
+
+layout(ANKI_TEX_BINDING(0, 3)) uniform samplerCubeArray u_irradianceTex;
+
+ANKI_PUSH_CONSTANTS(Vec4, u_faceIdxPad3);
+
+void main()
+{
+	// Compute the UVs to read the gbuffer from
+	Vec2 sampleUv = in_uv;
+	sampleUv.x *= (1.0 / 6.0);
+	sampleUv.x += (1.0 / 6.0) * u_faceIdxPad3.x;
+
+	// Read the gbuffer
+	GbufferInfo gbuffer;
+	readGBuffer(u_gbufferTex0, u_gbufferTex1, u_gbufferTex2, sampleUv, 0.0, gbuffer);
+
+	// Read the irradiance. Use the layer 0 because the C++ sets an appropriate texture view
+	Vec3 irradiance = textureLod(u_irradianceTex, Vec4(gbuffer.m_normal, 0.0), 0.0).rgb;
+
+	// Compute the indirect term
+	Vec3 indirect = gbuffer.m_diffuse * irradiance;
+
+	// Write it
+	out_color = indirect;
+}
+			]]></source>
+		</shader>
+	</shaders>
+</shaderProgram>

+ 3 - 8
shaders/Irradiance.ankiprog

@@ -28,18 +28,13 @@ layout(location = 0) out Vec3 out_color;
 
 layout(ANKI_TEX_BINDING(0, 0)) uniform samplerCubeArray u_envTex;
 
-layout(ANKI_UBO_BINDING(0, 0)) uniform u0_
-{
-	// x: The face index to render to
-	// y: The array index to read from the u_envTex
-	UVec4 u_faceIdxArrayIdxPad2;
-};
+ANKI_PUSH_CONSTANTS(UVec4, u_faceIdxPad3);
 
 // Integrate the environment map to compute the irradiance for a single fragment
 void main()
 {
-	U32 face = u_faceIdxArrayIdxPad2.x;
-	F32 texArrIdx = F32(u_faceIdxArrayIdxPad2.y);
+	U32 face = u_faceIdxPad3.x;
+	const F32 texArrIdx = 0.0; // The C++ code gives the layer idx using a tex view
 
 	// Get the r coordinate of the current face and fragment
 	Vec3 ri = getCubemapDirection(UV_TO_NDC(in_uv), face);

+ 1 - 1
shaders/Pack.glsl

@@ -159,7 +159,7 @@ void readNormalFromGBuffer(in sampler2D rt2, in Vec2 uv, out Vec3 normal)
 }
 
 // Read from the G buffer
-void readGBuffer(in sampler2D rt0, in sampler2D rt1, in sampler2D rt2, in Vec2 uv, in F32 lod, out GbufferInfo g)
+void readGBuffer(sampler2D rt0, sampler2D rt1, sampler2D rt2, Vec2 uv, F32 lod, out GbufferInfo g)
 {
 	Vec4 comp = textureLod(rt0, uv, 0.0);
 	g.m_diffuse = comp.xyz;

+ 145 - 32
src/anki/renderer/Indirect.cpp

@@ -49,6 +49,7 @@ Error Indirect::initInternal(const ConfigSet& config)
 	ANKI_CHECK(initGBuffer(config));
 	ANKI_CHECK(initLightShading(config));
 	ANKI_CHECK(initIrradiance(config));
+	ANKI_CHECK(initIrradianceToRefl(config));
 
 	// Load split sum integration LUT
 	ANKI_CHECK(getResourceManager().loadResource("engine_data/SplitSumIntegration.ankitex", m_integrationLut));
@@ -172,6 +173,19 @@ Error Indirect::initIrradiance(const ConfigSet& config)
 	return Error::NONE;
 }
 
+Error Indirect::initIrradianceToRefl(const ConfigSet& cfg)
+{
+	// Create program
+	ANKI_CHECK(m_r->getResourceManager().loadResource(
+		"shaders/ApplyIrradianceToReflection.ankiprog", m_irradianceToRefl.m_prog));
+
+	const ShaderProgramResourceVariant* variant;
+	m_irradianceToRefl.m_prog->getOrCreateVariant(variant);
+	m_irradianceToRefl.m_grProg = variant->getProgram();
+
+	return Error::NONE;
+}
+
 void Indirect::initCacheEntry(U32 cacheEntryIdx)
 {
 	CacheEntry& cacheEntry = m_cacheEntries[cacheEntryIdx];
@@ -199,6 +213,17 @@ void Indirect::initCacheEntry(U32 cacheEntryIdx)
 			fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::DONT_CARE;
 			fbDescr.bake();
 		}
+
+		// Irradiance to Refl FB
+		{
+			FramebufferDescription& fbDescr = cacheEntry.m_irradianceToReflFbDescrs[faceIdx];
+			ANKI_ASSERT(!fbDescr.isBacked());
+			fbDescr.m_colorAttachmentCount = 1;
+			fbDescr.m_colorAttachments[0].m_surface.m_layer = cacheEntryIdx;
+			fbDescr.m_colorAttachments[0].m_surface.m_face = faceIdx;
+			fbDescr.m_colorAttachments[0].m_loadOperation = AttachmentLoadOperation::LOAD;
+			fbDescr.bake();
+		}
 	}
 }
 
@@ -400,19 +425,57 @@ void Indirect::runIrradiance(U32 faceIdx, RenderPassWorkContext& rgraphCtx)
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 
 	// Set state
-	cmdb->bindShaderProgram(m_irradiance.m_grProg);
-	rgraphCtx.bindColorTextureAndSampler(0, 0, m_ctx.m_lightShadingRt, m_r->getLinearSampler());
 	cmdb->setViewport(0, 0, m_irradiance.m_tileSize, m_irradiance.m_tileSize);
+	cmdb->bindShaderProgram(m_irradiance.m_grProg);
+
+	TextureSubresourceInfo subresource;
+	subresource.m_faceCount = 6;
+	subresource.m_firstLayer = cacheEntryIdx;
+	rgraphCtx.bindTextureAndSampler(0, 0, m_ctx.m_lightShadingRt, subresource, m_r->getLinearSampler());
 
 	// Set uniforms
-	UVec4* faceIdxArrayIdx = allocateAndBindUniforms<UVec4*>(sizeof(UVec4), cmdb, 0, 0);
-	faceIdxArrayIdx->x() = faceIdx;
-	faceIdxArrayIdx->y() = cacheEntryIdx;
+	UVec4 pushConsts(faceIdx);
+	cmdb->setPushConstants(&pushConsts, sizeof(pushConsts));
 
 	// Draw
 	drawQuad(cmdb);
 }
 
+void Indirect::runIrradianceToRefl(U32 faceIdx, RenderPassWorkContext& rgraphCtx)
+{
+	ANKI_ASSERT(faceIdx < 6);
+	ANKI_TRACE_SCOPED_EVENT(R_IR);
+
+	const U32 cacheEntryIdx = m_ctx.m_cacheEntryIdx;
+	ANKI_ASSERT(cacheEntryIdx < m_cacheEntries.getSize());
+
+	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
+
+	// Set state
+	cmdb->setViewport(0, 0, m_lightShading.m_tileSize, m_lightShading.m_tileSize);
+	cmdb->setBlendFactors(0, BlendFactor::ONE, BlendFactor::ONE);
+
+	cmdb->bindShaderProgram(m_irradianceToRefl.m_grProg);
+
+	rgraphCtx.bindColorTextureAndSampler(0, 0, m_ctx.m_gbufferColorRts[0], m_r->getNearestSampler());
+	rgraphCtx.bindColorTextureAndSampler(0, 1, m_ctx.m_gbufferColorRts[1], m_r->getNearestSampler());
+	rgraphCtx.bindColorTextureAndSampler(0, 2, m_ctx.m_gbufferColorRts[2], m_r->getNearestSampler());
+
+	TextureSubresourceInfo subresource;
+	subresource.m_faceCount = 6;
+	subresource.m_firstLayer = cacheEntryIdx;
+	rgraphCtx.bindTextureAndSampler(0, 3, m_ctx.m_irradianceRt, subresource, m_r->getLinearSampler());
+
+	Vec4 pushConsts(faceIdx);
+	cmdb->setPushConstants(&pushConsts, sizeof(pushConsts));
+
+	// Draw
+	drawQuad(cmdb);
+
+	// Restore state
+	cmdb->setBlendFactors(0, BlendFactor::ONE, BlendFactor::ZERO);
+}
+
 void Indirect::populateRenderGraph(RenderingContext& rctx)
 {
 	ANKI_TRACE_SCOPED_EVENT(R_IR);
@@ -507,30 +570,6 @@ void Indirect::populateRenderGraph(RenderingContext& rctx)
 			}
 		}
 
-		// Mipmapping "passes"
-		{
-			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);
-
-				TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
-				subresource.m_mipmapCount = m_lightShading.m_mipCount;
-
-				pass.newConsumer({m_ctx.m_lightShadingRt, TextureUsageBit::GENERATE_MIPMAPS, subresource});
-				pass.newProducer({m_ctx.m_lightShadingRt, TextureUsageBit::GENERATE_MIPMAPS, subresource});
-			}
-		}
-
 		// Irradiance passes
 		{
 			static const Array<RenderPassWorkCallback, 6> callbacks = {{runIrradianceCallback<0>,
@@ -555,11 +594,85 @@ void Indirect::populateRenderGraph(RenderingContext& rctx)
 
 				pass.setWork(callbacks[faceIdx], this, 0);
 
-				pass.newConsumer({m_ctx.m_lightShadingRt, TextureUsageBit::SAMPLED_FRAGMENT});
+				// Read a cube but only one layer and level
+				TextureSubresourceInfo readSubresource;
+				readSubresource.m_faceCount = 6;
+				readSubresource.m_firstLayer = probeToUpdateCacheEntryIdx;
+				pass.newConsumer({m_ctx.m_lightShadingRt, TextureUsageBit::SAMPLED_FRAGMENT, readSubresource});
+
+				TextureSubresourceInfo writeSubresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
+				pass.newConsumer(
+					{m_ctx.m_irradianceRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, writeSubresource});
+				pass.newProducer(
+					{m_ctx.m_irradianceRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, writeSubresource});
+			}
+		}
+
+		// 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)
+			{
+				GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
+
+				pass.setFramebufferInfo(m_cacheEntries[probeToUpdateCacheEntryIdx].m_irradianceToReflFbDescrs[faceIdx],
+					{{m_ctx.m_lightShadingRt}},
+					{});
+
+				pass.setWork(callbacks[faceIdx], this, 0);
+
+				for(U i = 0; i < GBUFFER_COLOR_ATTACHMENT_COUNT; ++i)
+				{
+					pass.newConsumer({m_ctx.m_gbufferColorRts[i], TextureUsageBit::SAMPLED_FRAGMENT});
+				}
+
+				TextureSubresourceInfo readSubresource;
+				readSubresource.m_faceCount = 6;
+				readSubresource.m_firstLayer = probeToUpdateCacheEntryIdx;
+				pass.newConsumer({m_ctx.m_irradianceRt, TextureUsageBit::SAMPLED_FRAGMENT, readSubresource});
+
+				TextureSubresourceInfo writeSubresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
+				pass.newConsumer(
+					{m_ctx.m_lightShadingRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE, writeSubresource});
+				pass.newProducer(
+					{m_ctx.m_lightShadingRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_READ_WRITE, writeSubresource});
+			}
+		}
+
+		// Mipmapping "passes"
+		{
+			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);
 
 				TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, probeToUpdateCacheEntryIdx));
-				pass.newConsumer({m_ctx.m_irradianceRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, subresource});
-				pass.newProducer({m_ctx.m_irradianceRt, TextureUsageBit::FRAMEBUFFER_ATTACHMENT_WRITE, subresource});
+				subresource.m_mipmapCount = m_lightShading.m_mipCount;
+
+				pass.newConsumer({m_ctx.m_lightShadingRt, TextureUsageBit::GENERATE_MIPMAPS, subresource});
+				pass.newProducer({m_ctx.m_lightShadingRt, TextureUsageBit::GENERATE_MIPMAPS, subresource});
 			}
 		}
 	}

+ 22 - 4
src/anki/renderer/Indirect.h

@@ -93,6 +93,13 @@ private:
 		ShaderProgramPtr m_grProg;
 	} m_irradiance; ///< Irradiance.
 
+	class
+	{
+	public:
+		ShaderProgramResourcePtr m_prog;
+		ShaderProgramPtr m_grProg;
+	} m_irradianceToRefl; ///< Apply irradiance back to the reflection.
+
 	class CacheEntry
 	{
 	public:
@@ -101,6 +108,7 @@ private:
 
 		Array<FramebufferDescription, 6> m_lightShadingFbDescrs;
 		Array<FramebufferDescription, 6> m_irradianceFbDescrs;
+		Array<FramebufferDescription, 6> m_irradianceToReflFbDescrs;
 	};
 
 	DynamicArray<CacheEntry> m_cacheEntries;
@@ -126,6 +134,7 @@ private:
 	ANKI_USE_RESULT Error initGBuffer(const ConfigSet& cfg);
 	ANKI_USE_RESULT Error initLightShading(const ConfigSet& cfg);
 	ANKI_USE_RESULT Error initIrradiance(const ConfigSet& cfg);
+	ANKI_USE_RESULT Error initIrradianceToRefl(const ConfigSet& cfg);
 
 	/// Lazily init the cache entry
 	void initCacheEntry(U32 cacheEntryIdx);
@@ -140,11 +149,12 @@ private:
 	void runLightShading(U32 faceIdx, RenderPassWorkContext& rgraphCtx);
 	void runMipmappingOfLightShading(U32 faceIdx, RenderPassWorkContext& rgraphCtx);
 	void runIrradiance(U32 faceIdx, RenderPassWorkContext& rgraphCtx);
+	void runIrradianceToRefl(U32 faceIdx, RenderPassWorkContext& rgraphCtx);
 
 	// A RenderPassWorkCallback for G-buffer pass
 	static void runGBufferCallback(RenderPassWorkContext& rgraphCtx)
 	{
-		Indirect* const self = scast<Indirect*>(rgraphCtx.m_userData);
+		Indirect* const self = static_cast<Indirect*>(rgraphCtx.m_userData);
 		self->runGBuffer(rgraphCtx.m_commandBuffer);
 	}
 
@@ -152,7 +162,7 @@ private:
 	template<U faceIdx>
 	static void runLightShadingCallback(RenderPassWorkContext& rgraphCtx)
 	{
-		Indirect* const self = scast<Indirect*>(rgraphCtx.m_userData);
+		Indirect* const self = static_cast<Indirect*>(rgraphCtx.m_userData);
 		self->runLightShading(faceIdx, rgraphCtx);
 	}
 
@@ -160,7 +170,7 @@ private:
 	template<U faceIdx>
 	static void runMipmappingOfLightShadingCallback(RenderPassWorkContext& rgraphCtx)
 	{
-		Indirect* const self = scast<Indirect*>(rgraphCtx.m_userData);
+		Indirect* const self = static_cast<Indirect*>(rgraphCtx.m_userData);
 		self->runMipmappingOfLightShading(faceIdx, rgraphCtx);
 	}
 
@@ -168,9 +178,17 @@ private:
 	template<U faceIdx>
 	static void runIrradianceCallback(RenderPassWorkContext& rgraphCtx)
 	{
-		Indirect* const self = scast<Indirect*>(rgraphCtx.m_userData);
+		Indirect* const self = static_cast<Indirect*>(rgraphCtx.m_userData);
 		self->runIrradiance(faceIdx, rgraphCtx);
 	}
+
+	// A RenderPassWorkCallback to apply the irradiance back to the reflection.
+	template<U faceIdx>
+	static void runIrradianceToReflCallback(RenderPassWorkContext& rgraphCtx)
+	{
+		Indirect* const self = static_cast<Indirect*>(rgraphCtx.m_userData);
+		self->runIrradianceToRefl(faceIdx, rgraphCtx);
+	}
 };
 /// @}
 

+ 2 - 14
src/anki/renderer/LightBin.cpp

@@ -67,7 +67,7 @@ public:
 	ClusterProbeIndex()
 	{
 		// Do nothing. No need to initialize
-		static_assert(sizeof(ClusterProbeIndex) == sizeof(U16) * 2, "Because we memcmp");
+		static_assert(sizeof(ClusterProbeIndex) == sizeof(U16), "Because we memcmp");
 	}
 
 	U getIndex() const
@@ -81,22 +81,13 @@ public:
 		m_index = i;
 	}
 
-	void setProbeVolume(F32 v)
-	{
-		ANKI_ASSERT(v < MAX_PROBE_VOLUME);
-		m_probeVolume = v / F32(MAX_PROBE_VOLUME) * F32(MAX_U16);
-	}
-
 	Bool operator<(const ClusterProbeIndex& b) const
 	{
-		ANKI_ASSERT(m_probeVolume > 0 && b.m_probeVolume > 0);
-		return (m_probeVolume != b.m_probeVolume) ? (m_probeVolume > b.m_probeVolume) : (m_index < b.m_index);
+		return m_index < b.m_index;
 	}
 
 private:
-	static const U MAX_PROBE_VOLUME = 1000;
 	U16 m_index;
-	U16 m_probeVolume;
 };
 
 /// WARNING: Keep it as small as possible. The number of clusters is huge
@@ -736,9 +727,6 @@ void LightBin::writeAndBinProbe(
 
 		i = cluster.m_probeCount.fetchAdd(1) % MAX_PROBES_PER_CLUSTER;
 		cluster.m_probeIds[i].setIndex(idx);
-
-		Vec3 edges = probeEl.m_aabbMax - probeEl.m_aabbMin;
-		cluster.m_probeIds[i].setProbeVolume(edges.x() * edges.y() * edges.z());
 	}
 }