Browse Source

More GI work

Panagiotis Christopoulos Charitos 6 years ago
parent
commit
6ca4471093

+ 25 - 13
shaders/GlobalIlluminationClipmapPopulation.glslp

@@ -8,22 +8,15 @@
 #pragma anki input const U32 CLIPMAP_LEVEL_COUNT
 #pragma anki input const UVec3 WORKGROUP_SIZE
 #pragma anki input const U32 PROBE_COUNT
+#pragma anki mutator HAS_PROBES 0 1
 
 #pragma anki start comp
 
-#include <shaders/ClusteredShading.h>
+#include <shaders/glsl_cpp_common/ClusteredShading.h>
+#include <shaders/Functions.glsl>
 
 layout(local_size_x = WORKGROUP_SIZE.x, local_size_y = WORKGROUP_SIZE.y, local_size_z = WORKGROUP_SIZE.z) in;
 
-layout(set = 0, binding = 0) buffer ssbo_
-{
-	GlobalIlluminationProbe u_probes[];
-};
-
-layout(set = 0, binding = 1) uniform sampler u_linearAnyClampSampler;
-layout(set = 0, binding = 2) uniform texture3D u_probeIrradianceTextures[6u * PROBE_COUNT];
-layout(set = 0, binding = 3) uniform writeonly image3D u_clipmapImages[6u * CLIPMAP_LEVEL_COUNT];
-
 struct Clipmap
 {
 	Vec3 m_aabbMin;
@@ -34,13 +27,25 @@ struct Clipmap
 	U32 m_padding2;
 };
 
-layout(set = 0, binding = 4, std140) uniform ubo_
+layout(set = 0, binding = 0, std140) uniform ubo_
 {
 	Clipmap u_clipmaps[CLIPMAP_LEVEL_COUNT];
 	Vec3 u_cameraPos;
 	U32 u_padding;
 };
 
+layout(set = 0, binding = 1) uniform writeonly image3D u_clipmapImages[6u * CLIPMAP_LEVEL_COUNT];
+
+#if HAS_PROBES
+layout(set = 0, binding = 2) buffer ssbo_
+{
+	GlobalIlluminationProbe u_probes[];
+};
+
+layout(set = 0, binding = 3) uniform sampler u_linearAnyClampSampler;
+layout(set = 0, binding = 4) uniform texture3D u_probeIrradianceTextures[6u * PROBE_COUNT];
+#endif
+
 Bool aabbsOverlap(const Clipmap clipmap, const GlobalIlluminationProbe probe)
 {
 	return aabbsOverlap(clipmap.m_aabbMin, clipmap.m_aabbMax, probe.m_aabbMin, probe.m_aabbMax);
@@ -67,6 +72,7 @@ void main()
 			continue;
 		}
 
+#if HAS_PROBES
 		// For all probes
 		F32 weight = EPSILON;
 		Vec3 accumulatedIrradiance[6u] = Vec3[](Vec3(0.0), Vec3(0.0), Vec3(0.0), Vec3(0.0), Vec3(0.0), Vec3(0.0));
@@ -88,9 +94,10 @@ void main()
 				ANKI_UNROLL for(U32 dirIdx = 0u; dirIdx < 6u; ++dirIdx)
 				{
 					// Read the color from the probe
-					const U32 inputTexIdx = propeIdx * 6u + dirIdx;
+					const U32 inputTexIdx = probeIdx * 6u + dirIdx;
 					const Vec3 inColor = textureLod(
-						u_probeIrradianceTextures[inputTexIdx], u_linearAnyClampSampler, texCoordsInProbe, 0.0);
+						u_probeIrradianceTextures[inputTexIdx], u_linearAnyClampSampler, texCoordsInProbe, 0.0)
+											 .rgb;
 
 					accumulatedIrradiance[dirIdx] += inColor;
 				}
@@ -98,13 +105,18 @@ void main()
 				weight += 1.0;
 			}
 		}
+#endif
 
 		// Write the result
 		ANKI_UNROLL for(U32 dirIdx = 0u; dirIdx < 6u; ++dirIdx)
 		{
 			const U32 clipmapImageIdx = clipmapIdx * 6u + dirIdx;
 
+#if HAS_PROBES
 			const Vec3 storedColor = accumulatedIrradiance[dirIdx] / weight;
+#else
+			const Vec3 storedColor = Vec3(0.0);
+#endif
 			imageStore(u_clipmapImages[clipmapImageIdx], IVec3(gl_GlobalInvocationID), Vec4(storedColor, 0.0));
 		}
 	}

+ 34 - 0
shaders/IrradianceDice.glslp

@@ -13,6 +13,8 @@
 #include <shaders/Pack.glsl>
 #include <shaders/LightFunctions.glsl>
 
+#define DEBUG_MODE 0 // 0: disable, 1: different color per dice face, 2: different color per cell
+
 layout(local_size_x = INPUT_TEXTURES_HEIGHT, local_size_y = INPUT_TEXTURES_HEIGHT, local_size_z = 1) in;
 
 layout(set = 0, binding = 0) uniform sampler u_nearestAnyClampSampler;
@@ -152,8 +154,40 @@ void main()
 	{
 		ANKI_UNROLL for(U32 f = 0u; f < 6u; ++f)
 		{
+#if DEBUG_MODE == 0
 			Vec3 irradiance = u_integrationResults[f][0];
 			irradiance /= PI; // Pre-divide
+			const Vec3 toStoreValue = irradiance;
+#elif DEBUG_MODE == 1
+			Vec3 toStoreValue;
+			switch(f)
+			{
+			case 0:
+				toStoreValue = Vec3(1.0, 0.0, 0.0);
+				break;
+			case 1:
+				toStoreValue = Vec3(0.5, 0.0, 0.0);
+				break;
+			case 2:
+				toStoreValue = Vec3(0.0, 1.0, 0.0);
+				break;
+			case 3:
+				toStoreValue = Vec3(0.0, 0.5, 0.0);
+				break;
+			case 4:
+				toStoreValue = Vec3(0.0, 0.0, 1.0);
+				break;
+			default:
+				toStoreValue = Vec3(0.0, 0.0, 0.5);
+			}
+#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 Vec3 toStoreValue = heatmap(headmapFactor);
+#endif
+
 			imageStore(u_irradianceVolumes[f], u_volumeTexel, Vec4(irradiance, 0.0));
 		}
 	}

+ 5 - 1
src/anki/core/Config.cpp

@@ -46,8 +46,12 @@ Config::Config()
 	newOption("r.indirect.shadowMapResolution", 64);
 
 	newOption("r.gi.tileResolution", 32);
-	newOption("r.gi.maxSimultaneousProbeCount", 16);
 	newOption("r.gi.shadowMapResolution", 128);
+	newOption("r.gi.maxCachedProbes", 16);
+	newOption("r.gi.maxVisibleProbes", 4);
+	newOption("r.gi.firstClipmapLevelCellSize", 1.0);
+	newOption("r.gi.secondClipmapLevelCellSize", 8.0);
+	newOption("r.gi.firstClipmapMaxDistance", 20.0);
 
 	newOption("r.motionBlur.maxSamples", 32);
 

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

@@ -96,11 +96,11 @@ void GBufferPost::run(RenderPassWorkContext& rgraphCtx)
 
 	cmdb->bindTexture(0,
 		5,
-		(rsrc.m_diffDecalTexView) ? rsrc.m_diffDecalTexView : m_r->getDummyTextureView(),
+		(rsrc.m_diffDecalTexView) ? rsrc.m_diffDecalTexView : m_r->getDummyTextureView2d(),
 		TextureUsageBit::SAMPLED_FRAGMENT);
 	cmdb->bindTexture(0,
 		6,
-		(rsrc.m_specularRoughnessDecalTexView) ? rsrc.m_specularRoughnessDecalTexView : m_r->getDummyTextureView(),
+		(rsrc.m_specularRoughnessDecalTexView) ? rsrc.m_specularRoughnessDecalTexView : m_r->getDummyTextureView2d(),
 		TextureUsageBit::SAMPLED_FRAGMENT);
 
 	bindStorage(cmdb, 0, 7, rsrc.m_clustersToken);

+ 74 - 52
src/anki/renderer/GlobalIllumination.cpp

@@ -20,19 +20,18 @@ static Vec3 computeProbeCellPosition(U cellIdx, const GlobalIlluminationProbeQue
 	ANKI_ASSERT(cellIdx < probe.m_totalCellCount);
 
 	UVec3 cellCoords;
-	unflatten3dArrayIndex(probe.m_cellCounts.x(),
+	unflatten3dArrayIndex(probe.m_cellCounts.z(),
 		probe.m_cellCounts.y(),
-		probe.m_cellCounts.z(),
+		probe.m_cellCounts.x(),
 		cellIdx,
-		cellCoords.x(),
+		cellCoords.z(),
 		cellCoords.y(),
-		cellCoords.z());
+		cellCoords.x());
 
-	const Vec3 cellSize = (probe.m_aabbMax - probe.m_aabbMin)
-						  / Vec3(probe.m_cellCounts.x(), probe.m_cellCounts.y(), probe.m_cellCounts.z());
-	const Vec3 halfCellSize = cellSize / 2.0f;
+	const F32 halfCellSize = probe.m_cellSize / 2.0f;
 	const Vec3 cellPos =
-		Vec3(cellCoords.x(), cellCoords.y(), cellCoords.z()) * cellSize + halfCellSize + probe.m_aabbMin;
+		Vec3(cellCoords.x(), cellCoords.y(), cellCoords.z()) * probe.m_cellSize + halfCellSize + probe.m_aabbMin;
+	ANKI_ASSERT(cellPos < probe.m_aabbMax);
 
 	return cellPos;
 }
@@ -56,6 +55,11 @@ public:
 
 	Array<Aabb, CLIPMAP_LEVEL_COUNT> m_clipmapLevelAabbs; ///< AABBs in world space.
 	UVec3 m_maxClipmapVolumeSize = UVec3(0u);
+
+	static void foo()
+	{
+		static_assert(std::is_trivially_destructible<InternalContext>::value, "See file");
+	}
 };
 
 GlobalIllumination::~GlobalIllumination()
@@ -65,6 +69,13 @@ GlobalIllumination::~GlobalIllumination()
 	m_clipmap.m_grProgs.destroy(getAllocator());
 }
 
+const Array2d<RenderTargetHandle, GlobalIllumination::CLIPMAP_LEVEL_COUNT, 6>&
+GlobalIllumination::getClipmapVolumeRenderTargets() const
+{
+	ANKI_ASSERT(m_giCtx);
+	return m_giCtx->m_clipmapRts;
+}
+
 Error GlobalIllumination::init(const ConfigSet& cfg)
 {
 	ANKI_R_LOGI("Initializing global illumination");
@@ -83,6 +94,7 @@ Error GlobalIllumination::initInternal(const ConfigSet& cfg)
 	m_tileSize = cfg.getNumber("r.gi.tileResolution");
 	m_cacheEntries.create(getAllocator(), cfg.getNumber("r.gi.maxCachedProbes"));
 	m_maxVisibleProbes = cfg.getNumber("r.gi.maxVisibleProbes");
+	ANKI_ASSERT(m_cacheEntries.getSize() >= m_maxVisibleProbes);
 
 	ANKI_CHECK(initGBuffer(cfg));
 	ANKI_CHECK(initLightShading(cfg));
@@ -205,25 +217,30 @@ Error GlobalIllumination::initClipmap(const ConfigSet& cfg)
 {
 	// Init the program
 	ANKI_CHECK(
-		m_r->getResourceManager().loadResource("shaders/GlobalIlluminationClimpamPopulation.glslp", m_clipmap.m_prog));
+		m_r->getResourceManager().loadResource("shaders/GlobalIlluminationClipmapPopulation.glslp", m_clipmap.m_prog));
 
 	m_clipmap.m_grProgs.create(getAllocator(), m_maxVisibleProbes + 1);
 
 	ShaderProgramResourceConstantValueInitList<3> consts(m_clipmap.m_prog);
+	consts.add("PROBE_COUNT", U32(0));
 	consts.add("CLIPMAP_LEVEL_COUNT", U32(CLIPMAP_LEVEL_COUNT));
 	consts.add("WORKGROUP_SIZE",
 		UVec3(m_clipmap.m_workgroupSize[0], m_clipmap.m_workgroupSize[1], m_clipmap.m_workgroupSize[2]));
-	consts.add("PROBE_COUNT", U32(0));
+
+	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[2].m_uint = U32(probeCount);
-		m_clipmap.m_prog->getOrCreateVariant(consts.get(), 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(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");
@@ -240,6 +257,7 @@ void GlobalIllumination::populateRenderGraph(RenderingContext& rctx)
 	giCtx->m_gi = this;
 	giCtx->m_ctx = &rctx;
 	RenderGraphDescription& rgraph = rctx.m_renderGraphDescr;
+	m_giCtx = giCtx;
 
 	// Prepare the probes
 	prepareProbes(rctx, giCtx->m_probe, giCtx->m_cell);
@@ -736,44 +754,6 @@ void GlobalIllumination::runClipmapPopulation(RenderPassWorkContext& rgraphCtx,
 
 	CommandBufferPtr& cmdb = rgraphCtx.m_commandBuffer;
 
-	// Allocate and bin the probes
-	GlobalIlluminationProbe* probes = allocateAndBindStorage<GlobalIlluminationProbe*>(
-		sizeof(GlobalIlluminationProbe) * giCtx.m_ctx->m_renderQueue->m_giProbes.getSize(), cmdb, 0, 0);
-	for(U i = 0; i < giCtx.m_ctx->m_renderQueue->m_giProbes.getSize(); ++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, 1, m_r->getSamplers().m_trilinearClamp);
-
-	// Bind input textures
-	for(U i = 0; i < giCtx.m_ctx->m_renderQueue->m_giProbes.getSize(); ++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, 2, rt, i * 6 + dir);
-		}
-	}
-
-	// Bind out textures
-	for(U level = 0; level < CLIPMAP_LEVEL_COUNT; ++level)
-	{
-		for(U dir = 0; dir < 6; ++dir)
-		{
-			rgraphCtx.bindColorTexture(0, 3, giCtx.m_clipmapRts[level][dir], level * 6 + dir);
-		}
-	}
-
 	// Allocate and bin uniforms
 	struct Clipmap
 	{
@@ -791,7 +771,7 @@ void GlobalIllumination::runClipmapPopulation(RenderPassWorkContext& rgraphCtx,
 		Vec3 m_cameraPos;
 		U32 m_padding;
 	};
-	Unis* unis = allocateAndBindUniforms<Unis*>(sizeof(Unis), cmdb, 0, 4);
+	Unis* unis = allocateAndBindUniforms<Unis*>(sizeof(Unis), cmdb, 0, 0);
 
 	for(U level = 0; level < CLIPMAP_LEVEL_COUNT; ++level)
 	{
@@ -804,6 +784,48 @@ void GlobalIllumination::runClipmapPopulation(RenderPassWorkContext& rgraphCtx,
 	}
 	unis->m_cameraPos = giCtx.m_ctx->m_renderQueue->m_cameraTransform.getTranslationPart().xyz();
 
+	// Bind out images
+	for(U level = 0; level < 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)
+	{
+		// 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);
+			}
+		}
+	}
+
 	// Bind the program
 	cmdb->bindShaderProgram(m_clipmap.m_grProgs[giCtx.m_ctx->m_renderQueue->m_giProbes.getSize()]);
 
@@ -872,7 +894,7 @@ void GlobalIllumination::populateRenderGraphClipmap(InternalContext& giCtx)
 		giCtx.m_maxClipmapVolumeSize = giCtx.m_maxClipmapVolumeSize.max(clipmapVolumeSize);
 
 		// Maximize the size of the volumes to avoid creating new RTs every frame
-		m_clipmap.m_volumeSizes[level] = clipmapVolumeSize.max(m_clipmap.m_volumeSizes[level]);
+		m_clipmap.m_volumeSizes[level] = m_clipmap.m_volumeSizes[level].max(clipmapVolumeSize);
 	}
 
 	// Create a few RT descriptors

+ 12 - 8
src/anki/renderer/GlobalIllumination.h

@@ -15,9 +15,14 @@ namespace anki
 /// @addtogroup renderer
 /// @{
 
-/// Global illumination.
+/// Ambient global illumination passes.
+///
+/// It builds a volume clipmap with ambient GI information.
 class GlobalIllumination : public RendererObject
 {
+private:
+	static constexpr U CLIPMAP_LEVEL_COUNT = 2;
+
 anki_internal:
 	GlobalIllumination(Renderer* r)
 		: RendererObject(r)
@@ -32,17 +37,15 @@ anki_internal:
 	/// Populate the rendergraph.
 	void populateRenderGraph(RenderingContext& ctx);
 
-	/// Given a probe return a volume render target that contains the irradiance.
-	const Array<RenderTargetHandle, 6>& getProbeVolumeRenderTargets(
-		const GlobalIlluminationProbeQueueElement& probe) const
+	/// Return a number of volume render targets.
+	const Array2d<RenderTargetHandle, CLIPMAP_LEVEL_COUNT, 6>& getClipmapVolumeRenderTargets() const;
+
+	static constexpr U getClipmapLevelCount()
 	{
-		const CacheEntry& entry = m_cacheEntries[probe.m_cacheEntryIndex];
-		ANKI_ASSERT(entry.m_uuid == probe.m_uuid);
-		return entry.m_rtHandles;
+		return CLIPMAP_LEVEL_COUNT;
 	}
 
 private:
-	static constexpr U CLIPMAP_LEVEL_COUNT = 2;
 	class InternalContext;
 
 	class CacheEntry
@@ -105,6 +108,7 @@ private:
 		Array<F32, CLIPMAP_LEVEL_COUNT - 1> m_levelMaxDistances;
 	} m_clipmap; ///< Clipmap population.
 
+	InternalContext* m_giCtx = nullptr;
 	DynamicArray<CacheEntry> m_cacheEntries;
 	HashMap<U64, U32> m_probeUuidToCacheEntryIdx;
 	U32 m_tileSize = 0;

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

@@ -102,11 +102,17 @@ Error Renderer::initInternal(const ConfigSet& config)
 		texinit.m_width = texinit.m_height = 4;
 		texinit.m_usage = TextureUsageBit::SAMPLED_ALL;
 		texinit.m_format = Format::R8G8B8A8_UNORM;
-		texinit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
+		texinit.m_initialUsage = TextureUsageBit::SAMPLED_ALL;
 		TexturePtr tex = getGrManager().newTexture(texinit);
 
 		TextureViewInitInfo viewinit(tex);
-		m_dummyTexView = getGrManager().newTextureView(viewinit);
+		m_dummyTexView2d = getGrManager().newTextureView(viewinit);
+
+		texinit.m_depth = 4;
+		texinit.m_type = TextureType::_3D;
+		tex = getGrManager().newTexture(texinit);
+		viewinit = TextureViewInitInfo(tex);
+		m_dummyTexView3d = getGrManager().newTextureView(viewinit);
 	}
 
 	m_dummyBuff = getGrManager().newBuffer(BufferInitInfo(

+ 9 - 3
src/anki/renderer/Renderer.h

@@ -317,9 +317,14 @@ anki_internal:
 		return m_resourcesDirty;
 	}
 
-	TextureViewPtr getDummyTextureView() const
+	TextureViewPtr getDummyTextureView2d() const
 	{
-		return m_dummyTexView;
+		return m_dummyTexView2d;
+	}
+
+	TextureViewPtr getDummyTextureView3d() const
+	{
+		return m_dummyTexView3d;
 	}
 
 	BufferPtr getDummyBuffer() const
@@ -410,7 +415,8 @@ private:
 	Array<Mat4, 16> m_jitteredMats16x;
 	Array<Mat4, 8> m_jitteredMats8x;
 
-	TextureViewPtr m_dummyTexView;
+	TextureViewPtr m_dummyTexView2d;
+	TextureViewPtr m_dummyTexView3d;
 	BufferPtr m_dummyBuff;
 
 	RendererPrecreatedSamplers m_samplers;

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

@@ -123,9 +123,9 @@ void VolumetricLightingAccumulation::run(RenderPassWorkContext& rgraphCtx)
 	rgraphCtx.bindColorTexture(0, 8, m_r->getShadowMapping().getShadowmapRt());
 
 	bindUniforms(cmdb, 0, 9, rsrc.m_probesToken);
-	cmdb->bindTexture(0, 10, m_r->getDummyTextureView(), TextureUsageBit::SAMPLED_COMPUTE);
+	cmdb->bindTexture(0, 10, m_r->getDummyTextureView2d(), TextureUsageBit::SAMPLED_COMPUTE);
 	rgraphCtx.bindColorTexture(0, 11, m_r->getIndirect().getIrradianceRt());
-	cmdb->bindTexture(0, 12, m_r->getDummyTextureView(), TextureUsageBit::SAMPLED_COMPUTE);
+	cmdb->bindTexture(0, 12, m_r->getDummyTextureView2d(), TextureUsageBit::SAMPLED_COMPUTE);
 
 	bindUniforms(cmdb, 0, 13, rsrc.m_fogDensityVolumesToken);
 	bindStorage(cmdb, 0, 14, rsrc.m_clustersToken);

+ 9 - 2
src/anki/scene/Visibility.cpp

@@ -62,8 +62,15 @@ void VisibilityContext::submitNewWork(const FrustumComponent& frc, RenderQueue&
 	rqueue.m_previousViewProjectionMatrix = frc.getPreviousViewProjectionMatrix();
 	rqueue.m_cameraNear = frc.getNear();
 	rqueue.m_cameraFar = frc.getFar();
-	rqueue.m_cameraFovX = frc.getFovX();
-	rqueue.m_cameraFovY = frc.getFovY();
+	if(frc.getFrustumType() == FrustumType::PERSPECTIVE)
+	{
+		rqueue.m_cameraFovX = frc.getFovX();
+		rqueue.m_cameraFovY = frc.getFovY();
+	}
+	else
+	{
+		rqueue.m_cameraFovX = rqueue.m_cameraFovY = 0.0f;
+	}
 	rqueue.m_effectiveShadowDistance = frc.getEffectiveShadowDistance();
 
 	auto alloc = m_scene->getFrameAllocator();