Răsfoiți Sursa

Add GPU light culling to probe generation

Panagiotis Christopoulos Charitos 2 ani în urmă
părinte
comite
58524c4c94

+ 1 - 0
AnKi/Gr/RenderGraph.inl.h

@@ -314,6 +314,7 @@ inline RenderTargetHandle RenderGraphDescription::newRenderTarget(const RenderTa
 inline BufferHandle RenderGraphDescription::importBuffer(Buffer* buff, BufferUsageBit usage, PtrSize offset, PtrSize range)
 {
 	// Checks
+	ANKI_ASSERT(buff);
 	if(range == kMaxPtrSize)
 	{
 		ANKI_ASSERT(offset < buff->getSize());

+ 32 - 11
AnKi/Renderer/IndirectDiffuseProbes.cpp

@@ -309,6 +309,18 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 		giCtx->m_shadowsRt = {};
 	}
 
+	// Light visibility
+	Array<GpuVisibilityNonRenderablesOutput, 6> lightVis;
+	for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
+	{
+		GpuVisibilityNonRenderablesInput in;
+		in.m_passesName = "GI light visibility";
+		in.m_objectType = GpuSceneNonRenderableObjectType::kLight;
+		in.m_viewProjectionMat = giCtx->m_probeToUpdateThisFrame->m_renderQueues[faceIdx]->m_viewProjectionMatrix;
+		in.m_rgraph = &rgraph;
+		getRenderer().getGpuVisibilityNonRenderables().populateRenderGraph(in, lightVis[faceIdx]);
+	}
+
 	// Light shading pass
 	{
 		// RT
@@ -316,9 +328,17 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 
 		// Pass
 		GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass("GI light shading");
+
+		Array<BufferOffsetRange, 6> visibleLightsBuffers;
+		for(U32 f = 0; f < 6; ++f)
+		{
+			visibleLightsBuffers[f] = lightVis[f].m_visiblesBuffer;
+			pass.newBufferDependency(lightVis[f].m_visiblesBufferHandle, BufferUsageBit::kStorageFragmentRead);
+		}
+
 		pass.setFramebufferInfo(m_lightShading.m_fbDescr, {giCtx->m_lightShadingRt});
-		pass.setWork(1, [this](RenderPassWorkContext& rgraphCtx) {
-			runLightShading(rgraphCtx);
+		pass.setWork(1, [this, visibleLightsBuffers](RenderPassWorkContext& rgraphCtx) {
+			runLightShading(visibleLightsBuffers, rgraphCtx);
 		});
 
 		pass.newTextureDependency(giCtx->m_lightShadingRt, TextureUsageBit::kFramebufferWrite);
@@ -424,7 +444,7 @@ void IndirectDiffuseProbes::runShadowmappingInThread(RenderPassWorkContext& rgra
 	// It's secondary, no need to restore the state
 }
 
-void IndirectDiffuseProbes::runLightShading(RenderPassWorkContext& rgraphCtx)
+void IndirectDiffuseProbes::runLightShading(const Array<BufferOffsetRange, 6>& lightVisBuffers, RenderPassWorkContext& rgraphCtx)
 {
 	ANKI_TRACE_SCOPED_EVENT(RIndirectDiffuse);
 
@@ -452,22 +472,23 @@ void IndirectDiffuseProbes::runLightShading(RenderPassWorkContext& rgraphCtx)
 		dsInfo.m_gbufferTexCoordsBias = Vec2(0.0f, 0.0f);
 		dsInfo.m_lightbufferTexCoordsBias = Vec2(-F32(faceIdx), 0.0f);
 		dsInfo.m_lightbufferTexCoordsScale = Vec2(1.0f / F32(m_tileSize), 1.0f / F32(m_tileSize));
-		dsInfo.m_cameraNear = rqueue.m_cameraNear;
-		dsInfo.m_cameraFar = rqueue.m_cameraFar;
-		dsInfo.m_directionalLight = (rqueue.m_directionalLight.isEnabled()) ? &rqueue.m_directionalLight : nullptr;
-		dsInfo.m_pointLights = rqueue.m_pointLights;
-		dsInfo.m_spotLights = rqueue.m_spotLights;
-		dsInfo.m_commandBuffer = &cmdb;
+
+		const Bool hasDirLight = rqueue.m_directionalLight.isEnabled();
+		dsInfo.m_effectiveShadowDistance =
+			(hasDirLight && rqueue.m_directionalLight.hasShadow()) ? rqueue.m_directionalLight.m_shadowCascadesDistances[0] : -1.0f;
+		dsInfo.m_dirLightMatrix = (hasDirLight) ? rqueue.m_directionalLight.m_textureMatrices[0] : Mat4::getIdentity();
+
+		dsInfo.m_visibleLightsBuffer = lightVisBuffers[faceIdx];
+
 		dsInfo.m_gbufferRenderTargets[0] = giCtx.m_gbufferColorRts[0];
 		dsInfo.m_gbufferRenderTargets[1] = giCtx.m_gbufferColorRts[1];
 		dsInfo.m_gbufferRenderTargets[2] = giCtx.m_gbufferColorRts[2];
 		dsInfo.m_gbufferDepthRenderTarget = giCtx.m_gbufferDepthRt;
-		if(dsInfo.m_directionalLight && dsInfo.m_directionalLight->hasShadow())
+		if(hasDirLight && rqueue.m_directionalLight.hasShadow())
 		{
 			dsInfo.m_directionalLightShadowmapRenderTarget = giCtx.m_shadowsRt;
 		}
 		dsInfo.m_renderpassContext = &rgraphCtx;
-		dsInfo.m_skybox = &giCtx.m_ctx->m_renderQueue->m_skybox;
 
 		m_lightShading.m_deferred.drawLights(dsInfo);
 	}

+ 1 - 1
AnKi/Renderer/IndirectDiffuseProbes.h

@@ -74,7 +74,7 @@ private:
 
 	void runGBufferInThread(RenderPassWorkContext& rgraphCtx) const;
 	void runShadowmappingInThread(RenderPassWorkContext& rgraphCtx) const;
-	void runLightShading(RenderPassWorkContext& rgraphCtx);
+	void runLightShading(const Array<BufferOffsetRange, 6>& lightVisBuffers, RenderPassWorkContext& rgraphCtx);
 	void runIrradiance(RenderPassWorkContext& rgraphCtx);
 };
 /// @}

+ 22 - 13
AnKi/Renderer/ProbeReflections.cpp

@@ -207,13 +207,11 @@ void ProbeReflections::runGBuffer(const Array<GpuVisibilityOutput, 6>& visOuts,
 	getRenderer().getSceneDrawer().drawMdi(args, cmdb);
 }
 
-void ProbeReflections::runLightShading(U32 faceIdx, const RenderingContext& rctx, RenderPassWorkContext& rgraphCtx)
+void ProbeReflections::runLightShading(U32 faceIdx, const BufferOffsetRange& visResult, RenderPassWorkContext& rgraphCtx)
 {
 	ANKI_ASSERT(faceIdx <= 6);
 	ANKI_TRACE_SCOPED_EVENT(RCubeRefl);
 
-	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
-
 	ANKI_ASSERT(m_ctx.m_probe);
 	const ReflectionProbeQueueElementForRefresh& probe = *m_ctx.m_probe;
 	const RenderQueue& rqueue = *probe.m_renderQueues[faceIdx];
@@ -228,22 +226,18 @@ void ProbeReflections::runLightShading(U32 faceIdx, const RenderingContext& rctx
 	dsInfo.m_gbufferTexCoordsBias = Vec2(F32(faceIdx) * (1.0f / 6.0f), 0.0f);
 	dsInfo.m_lightbufferTexCoordsScale = Vec2(1.0f / F32(m_lightShading.m_tileSize), 1.0f / F32(m_lightShading.m_tileSize));
 	dsInfo.m_lightbufferTexCoordsBias = Vec2(0.0f, 0.0f);
-	dsInfo.m_cameraNear = probe.m_renderQueues[faceIdx]->m_cameraNear;
-	dsInfo.m_cameraFar = probe.m_renderQueues[faceIdx]->m_cameraFar;
-	dsInfo.m_directionalLight = (hasDirLight) ? &probe.m_renderQueues[faceIdx]->m_directionalLight : nullptr;
-	dsInfo.m_pointLights = rqueue.m_pointLights;
-	dsInfo.m_spotLights = rqueue.m_spotLights;
-	dsInfo.m_commandBuffer = &cmdb;
+	dsInfo.m_effectiveShadowDistance = (hasDirLight) ? probe.m_renderQueues[faceIdx]->m_directionalLight.m_shadowCascadesDistances[0] : 0.0f;
+	dsInfo.m_dirLightMatrix = (hasDirLight) ? probe.m_renderQueues[faceIdx]->m_directionalLight.m_textureMatrices[0] : Mat4::getIdentity();
+	dsInfo.m_visibleLightsBuffer = visResult;
 	dsInfo.m_gbufferRenderTargets[0] = m_ctx.m_gbufferColorRts[0];
 	dsInfo.m_gbufferRenderTargets[1] = m_ctx.m_gbufferColorRts[1];
 	dsInfo.m_gbufferRenderTargets[2] = m_ctx.m_gbufferColorRts[2];
 	dsInfo.m_gbufferDepthRenderTarget = m_ctx.m_gbufferDepthRt;
-	if(hasDirLight && dsInfo.m_directionalLight->hasShadow())
+	if(hasDirLight && probe.m_renderQueues[faceIdx]->m_directionalLight.hasShadow())
 	{
 		dsInfo.m_directionalLightShadowmapRenderTarget = m_ctx.m_shadowMapRt;
 	}
 	dsInfo.m_renderpassContext = &rgraphCtx;
-	dsInfo.m_skybox = &rctx.m_renderQueue->m_skybox;
 
 	m_lightShading.m_deferred.drawLights(dsInfo);
 }
@@ -454,6 +448,18 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		m_ctx.m_shadowMapRt = {};
 	}
 
+	// Light visibility
+	Array<GpuVisibilityNonRenderablesOutput, 6> lightVis;
+	for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
+	{
+		GpuVisibilityNonRenderablesInput in;
+		in.m_passesName = "Cube refl light visibility";
+		in.m_objectType = GpuSceneNonRenderableObjectType::kLight;
+		in.m_viewProjectionMat = m_ctx.m_probe->m_renderQueues[faceIdx]->m_viewProjectionMatrix;
+		in.m_rgraph = &rgraph;
+		getRenderer().getGpuVisibilityNonRenderables().populateRenderGraph(in, lightVis[faceIdx]);
+	}
+
 	// Light shading passes
 	{
 		// RT
@@ -465,11 +471,14 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 		for(U32 faceIdx = 0; faceIdx < 6; ++faceIdx)
 		{
 			GraphicsRenderPassDescription& pass = rgraph.newGraphicsRenderPass(passNames[faceIdx]);
+
 			pass.setFramebufferInfo(m_lightShading.m_fbDescr[faceIdx], {m_ctx.m_lightShadingRt});
-			pass.setWork([this, faceIdx, &rctx](RenderPassWorkContext& rgraphCtx) {
-				runLightShading(faceIdx, rctx, rgraphCtx);
+			pass.setWork([this, visResult = lightVis[faceIdx].m_visiblesBuffer, faceIdx](RenderPassWorkContext& rgraphCtx) {
+				runLightShading(faceIdx, visResult, rgraphCtx);
 			});
 
+			pass.newBufferDependency(lightVis[faceIdx].m_visiblesBufferHandle, BufferUsageBit::kStorageFragmentRead);
+
 			TextureSubresourceInfo subresource(TextureSurfaceInfo(0, 0, faceIdx, 0));
 			pass.newTextureDependency(m_ctx.m_lightShadingRt, TextureUsageBit::kFramebufferWrite, subresource);
 

+ 1 - 1
AnKi/Renderer/ProbeReflections.h

@@ -121,7 +121,7 @@ private:
 
 	void runGBuffer(const Array<GpuVisibilityOutput, 6>& visOuts, RenderPassWorkContext& rgraphCtx);
 	void runShadowMapping(const Array<GpuVisibilityOutput, 6>& visOuts, RenderPassWorkContext& rgraphCtx);
-	void runLightShading(U32 faceIdx, const RenderingContext& ctx, RenderPassWorkContext& rgraphCtx);
+	void runLightShading(U32 faceIdx, const BufferOffsetRange& visResult, RenderPassWorkContext& rgraphCtx);
 	void runMipmappingOfLightShading(U32 faceIdx, RenderPassWorkContext& rgraphCtx);
 	void runIrradiance(RenderPassWorkContext& rgraphCtx);
 	void runIrradianceToRefl(RenderPassWorkContext& rgraphCtx);

+ 48 - 249
AnKi/Renderer/Utils/TraditionalDeferredShading.cpp

@@ -8,47 +8,14 @@
 #include <AnKi/Renderer/RenderQueue.h>
 #include <AnKi/Resource/ResourceManager.h>
 #include <AnKi/Resource/MeshResource.h>
+#include <AnKi/Resource/ImageResource.h>
 #include <AnKi/Shaders/Include/TraditionalDeferredShadingTypes.h>
+#include <AnKi/Scene/SceneGraph.h>
+#include <AnKi/Scene/Components/SkyboxComponent.h>
+#include <AnKi/Scene/Components/LightComponent.h>
 
 namespace anki {
 
-// Vertices of 2 shapes
-// - Use the blend file in EngineAssets to output in .obj and then copy paste here
-// - The sphere goes from -1 to 1
-// - The cone's length is 1. Its big side goes from -1 to 1. The point of the cone is in 0,0,0. The direction is in +z
-
-inline constexpr F32 kIcosphereVertices[] = {
-	0.000000f,  -1.067367f, 0.000000f,  0.772355f,  -0.477347f, 0.561142f,  -0.295008f, -0.477348f, 0.907955f,  -0.954681f, -0.477343f, 0.000000f,
-	-0.295008f, -0.477348f, -0.907955f, 0.772355f,  -0.477347f, -0.561142f, 0.295008f,  0.477348f,  0.907955f,  -0.772355f, 0.477347f,  0.561142f,
-	-0.772355f, 0.477347f,  -0.561142f, 0.295008f,  0.477348f,  -0.907955f, 0.954681f,  0.477343f,  0.000000f,  0.000000f,  1.067367f,  0.000000f,
-	-0.173400f, -0.907961f, 0.533679f,  0.453976f,  -0.907960f, 0.329829f,  0.280578f,  -0.561155f, 0.863513f,  0.907954f,  -0.561153f, 0.000000f,
-	0.453976f,  -0.907960f, -0.329829f, -0.561147f, -0.907958f, 0.000000f,  -0.734551f, -0.561154f, 0.533680f,  -0.173400f, -0.907961f, -0.533679f,
-	-0.734551f, -0.561154f, -0.533680f, 0.280578f,  -0.561155f, -0.863513f, 1.015128f,  0.000000f,  0.329830f,  1.015128f,  0.000000f,  -0.329830f,
-	0.000000f,  0.000000f,  1.067367f,  0.627383f,  0.000000f,  0.863518f,  -1.015128f, 0.000000f,  0.329830f,  -0.627383f, 0.000000f,  0.863518f,
-	-0.627383f, 0.000000f,  -0.863518f, -1.015128f, 0.000000f,  -0.329830f, 0.627383f,  0.000000f,  -0.863518f, 0.000000f,  0.000000f,  -1.067367f,
-	0.734551f,  0.561154f,  0.533680f,  -0.280578f, 0.561155f,  0.863513f,  -0.907954f, 0.561153f,  0.000000f,  -0.280578f, 0.561155f,  -0.863513f,
-	0.734551f,  0.561154f,  -0.533680f, 0.173400f,  0.907961f,  0.533679f,  0.561147f,  0.907958f,  0.000000f,  -0.453976f, 0.907960f,  0.329829f,
-	-0.453976f, 0.907960f,  -0.329829f, 0.173400f,  0.907961f,  -0.533679f};
-
-inline constexpr U16 kIconsphereIndices[] = {
-	0,  13, 12, 1,  13, 15, 0,  12, 17, 0,  17, 19, 0,  19, 16, 1,  15, 22, 2,  14, 24, 3,  18, 26, 4,  20, 28, 5,  21, 30, 1,  22, 25, 2,  24,
-	27, 3,  26, 29, 4,  28, 31, 5,  30, 23, 6,  32, 37, 7,  33, 39, 8,  34, 40, 9,  35, 41, 10, 36, 38, 38, 41, 11, 38, 36, 41, 36, 9,  41, 41,
-	40, 11, 41, 35, 40, 35, 8,  40, 40, 39, 11, 40, 34, 39, 34, 7,  39, 39, 37, 11, 39, 33, 37, 33, 6,  37, 37, 38, 11, 37, 32, 38, 32, 10, 38,
-	23, 36, 10, 23, 30, 36, 30, 9,  36, 31, 35, 9,  31, 28, 35, 28, 8,  35, 29, 34, 8,  29, 26, 34, 26, 7,  34, 27, 33, 7,  27, 24, 33, 24, 6,
-	33, 25, 32, 6,  25, 22, 32, 22, 10, 32, 30, 31, 9,  30, 21, 31, 21, 4,  31, 28, 29, 8,  28, 20, 29, 20, 3,  29, 26, 27, 7,  26, 18, 27, 18,
-	2,  27, 24, 25, 6,  24, 14, 25, 14, 1,  25, 22, 23, 10, 22, 15, 23, 15, 5,  23, 16, 21, 5,  16, 19, 21, 19, 4,  21, 19, 20, 4,  19, 17, 20,
-	17, 3,  20, 17, 18, 3,  17, 12, 18, 12, 2,  18, 15, 16, 5,  15, 13, 16, 13, 0,  16, 12, 14, 2,  12, 13, 14, 13, 1,  14};
-
-inline constexpr F32 kConeVertices[] = {0.000000f,  1.000000f,  -1.000000f, 0.000000f,  0.000000f,  0.000000f,  0.500000f,  0.866026f,  -1.000000f,
-										0.866025f,  0.500000f,  -1.000000f, 1.000000f,  0.000000f,  -1.000000f, 0.866025f,  -0.500000f, -1.000000f,
-										0.500000f,  -0.866025f, -1.000000f, 0.000000f,  -1.000000f, -1.000000f, -0.500000f, -0.866025f, -1.000000f,
-										-0.866025f, -0.500000f, -1.000000f, -1.000000f, -0.000000f, -1.000000f, -0.866026f, 0.500000f,  -1.000000f,
-										-0.500001f, 0.866025f,  -1.000000f, 0.000000f,  0.000000f,  -1.000000f};
-
-inline constexpr U16 kConeIndices[] = {0, 1,  2,  2,  1,  3,  3,  1,  4,  4,  1,  5,  5,  1,  6,  6,  1,  7,  7, 1,  8, 8, 1,  9,
-									   9, 1,  10, 10, 1,  11, 11, 1,  12, 12, 1,  0,  2,  13, 0,  0,  13, 12, 3, 13, 2, 4, 13, 3,
-									   5, 13, 4,  6,  13, 5,  7,  13, 6,  12, 13, 11, 11, 13, 10, 10, 13, 9,  9, 13, 8, 7, 8,  13};
-
 Error TraditionalDeferredLightShading::init()
 {
 	// Init progs
@@ -58,25 +25,14 @@ Error TraditionalDeferredLightShading::init()
 		for(U32 specular = 0; specular <= 1; ++specular)
 		{
 			ShaderProgramResourceVariantInitInfo variantInitInfo(m_lightProg);
-			variantInitInfo.addMutation("LIGHT_TYPE", 0);
 			variantInitInfo.addMutation("SPECULAR", specular);
 
 			const ShaderProgramResourceVariant* variant;
 			m_lightProg->getOrCreateVariant(variantInitInfo, variant);
-			m_plightGrProg[specular].reset(&variant->getProgram());
-
-			variantInitInfo.addMutation("LIGHT_TYPE", 1);
-			m_lightProg->getOrCreateVariant(variantInitInfo, variant);
-			m_slightGrProg[specular].reset(&variant->getProgram());
-
-			variantInitInfo.addMutation("LIGHT_TYPE", 2);
-			m_lightProg->getOrCreateVariant(variantInitInfo, variant);
-			m_dirLightGrProg[specular].reset(&variant->getProgram());
+			m_lightGrProg[specular].reset(&variant->getProgram());
 		}
 	}
 
-	createProxyMeshes();
-
 	// Shadow sampler
 	{
 		SamplerInitInfo inf;
@@ -104,87 +60,19 @@ Error TraditionalDeferredLightShading::init()
 	return Error::kNone;
 }
 
-void TraditionalDeferredLightShading::createProxyMeshes()
-{
-	constexpr PtrSize bufferSize = sizeof(kIcosphereVertices) + sizeof(kIcosphereVertices) + sizeof(kConeVertices) + sizeof(kConeIndices);
-
-	BufferInitInfo buffInit("DeferredShadingPoxies");
-	buffInit.m_size = bufferSize;
-	buffInit.m_usage = BufferUsageBit::kTransferDestination | BufferUsageBit::kIndex | BufferUsageBit::kVertex;
-
-	m_proxyVolumesBuffer = GrManager::getSingleton().newBuffer(buffInit);
-
-	buffInit.setName("TempTransfer");
-	buffInit.m_usage = BufferUsageBit::kTransferSource;
-	buffInit.m_mapAccess = BufferMapAccessBit::kWrite;
-	BufferPtr transferBuffer = GrManager::getSingleton().newBuffer(buffInit);
-
-	U8* mappedMem = static_cast<U8*>(transferBuffer->map(0, kMaxPtrSize, BufferMapAccessBit::kWrite));
-
-	// Write verts
-	memcpy(mappedMem, kIcosphereVertices, sizeof(kIcosphereVertices));
-	mappedMem += sizeof(kIcosphereVertices);
-	memcpy(mappedMem, kConeVertices, sizeof(kConeVertices));
-	mappedMem += sizeof(kConeVertices);
-	memcpy(mappedMem, kIconsphereIndices, sizeof(kIconsphereIndices));
-	mappedMem += sizeof(kIconsphereIndices);
-	memcpy(mappedMem, kConeIndices, sizeof(kConeIndices));
-
-	transferBuffer->unmap();
-
-	CommandBufferInitInfo cmdbInit("Temp");
-	cmdbInit.m_flags = CommandBufferFlag::kSmallBatch | CommandBufferFlag::kGeneralWork;
-
-	CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cmdbInit);
-	cmdb->copyBufferToBuffer(transferBuffer.get(), 0, m_proxyVolumesBuffer.get(), 0, bufferSize);
-	cmdb->flush();
-
-	GrManager::getSingleton().finish();
-}
-
-void TraditionalDeferredLightShading::bindVertexIndexBuffers(ProxyType proxyType, CommandBuffer& cmdb, U32& indexCount) const
-{
-	// Attrib
-	cmdb.setVertexAttribute(0, 0, Format::kR32G32B32_Sfloat, 0);
-
-	// Vert buff
-	PtrSize offset;
-	if(proxyType == ProxyType::kProxySphere)
-	{
-		offset = 0;
-	}
-	else
-	{
-		offset = sizeof(kIcosphereVertices);
-	}
-	cmdb.bindVertexBuffer(0, m_proxyVolumesBuffer.get(), offset, sizeof(Vec3));
-
-	// Idx buff
-	if(proxyType == ProxyType::kProxySphere)
-	{
-		offset = sizeof(kIcosphereVertices) + sizeof(kConeVertices);
-		indexCount = sizeof(kIconsphereIndices) / sizeof(U16);
-	}
-	else
-	{
-		offset = sizeof(kIcosphereVertices) + sizeof(kConeVertices) + sizeof(kIconsphereIndices);
-		indexCount = sizeof(kConeIndices) / sizeof(U16);
-	}
-
-	cmdb.bindIndexBuffer(m_proxyVolumesBuffer.get(), offset, IndexType::kU16);
-}
-
 void TraditionalDeferredLightShading::drawLights(TraditionalDeferredLightShadingDrawInfo& info)
 {
-	CommandBuffer& cmdb = *info.m_commandBuffer;
+	CommandBuffer& cmdb = *info.m_renderpassContext->m_commandBuffer;
 	RenderPassWorkContext& rgraphCtx = *info.m_renderpassContext;
 
 	// Set common state for all
 	cmdb.setViewport(info.m_viewport.x(), info.m_viewport.y(), info.m_viewport.z(), info.m_viewport.w());
 
 	// Skybox first
+	const SkyboxComponent* skyc = SceneGraph::getSingleton().getSkybox();
+	if(skyc)
 	{
-		const Bool isSolidColor = info.m_skybox->m_skyboxTexture == nullptr;
+		const Bool isSolidColor = (skyc->getSkyboxType() == SkyboxType::kSolidColor);
 
 		cmdb.bindShaderProgram(m_skyboxGrProgs[!isSolidColor].get());
 
@@ -194,11 +82,11 @@ void TraditionalDeferredLightShading::drawLights(TraditionalDeferredLightShading
 		if(!isSolidColor)
 		{
 			cmdb.bindSampler(0, 2, getRenderer().getSamplers().m_trilinearRepeatAniso.get());
-			cmdb.bindTexture(0, 3, info.m_skybox->m_skyboxTexture);
+			cmdb.bindTexture(0, 3, &skyc->getImageResource().getTextureView());
 		}
 
-		DeferredSkyboxUniforms unis;
-		unis.m_solidColor = info.m_skybox->m_solidColor;
+		TraditionalDeferredSkyboxUniforms unis;
+		unis.m_solidColor = (isSolidColor) ? skyc->getSolidColor() : Vec3(0.0f);
 		unis.m_inputTexUvBias = info.m_gbufferTexCoordsBias;
 		unis.m_inputTexUvScale = info.m_gbufferTexCoordsScale;
 		unis.m_invertedViewProjectionMat = info.m_invViewProjectionMatrix;
@@ -208,152 +96,63 @@ void TraditionalDeferredLightShading::drawLights(TraditionalDeferredLightShading
 		drawQuad(cmdb);
 	}
 
-	// Set common state for all light drawcalls
+	// Light shading
 	{
-		cmdb.setBlendFactors(0, BlendFactor::kOne, BlendFactor::kOne);
-
-		// NOTE: Use nearest sampler because we don't want the result to sample the near tiles
-		cmdb.bindSampler(0, 2, getRenderer().getSamplers().m_nearestNearestClamp.get());
+		const LightComponent* dirLightc = SceneGraph::getSingleton().getDirectionalLight();
 
-		rgraphCtx.bindColorTexture(0, 3, info.m_gbufferRenderTargets[0]);
-		rgraphCtx.bindColorTexture(0, 4, info.m_gbufferRenderTargets[1]);
-		rgraphCtx.bindColorTexture(0, 5, info.m_gbufferRenderTargets[2]);
-
-		rgraphCtx.bindTexture(0, 6, info.m_gbufferDepthRenderTarget, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
-
-		// Set shadowmap resources
-		cmdb.bindSampler(0, 7, m_shadowSampler.get());
-
-		if(info.m_directionalLight && info.m_directionalLight->hasShadow())
-		{
-			ANKI_ASSERT(info.m_directionalLightShadowmapRenderTarget.isValid());
-
-			rgraphCtx.bindTexture(0, 8, info.m_directionalLightShadowmapRenderTarget, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
-		}
-		else
-		{
-			// No shadows for the dir light, bind something random
-			rgraphCtx.bindColorTexture(0, 8, info.m_gbufferRenderTargets[0]);
-		}
-	}
-
-	// Dir light
-	if(info.m_directionalLight)
-	{
-		ANKI_ASSERT(info.m_directionalLight->m_uuid && info.m_directionalLight->m_shadowCascadeCount == 1);
-
-		cmdb.bindShaderProgram(m_dirLightGrProg[info.m_computeSpecular].get());
-
-		DeferredDirectionalLightUniforms* unis =
-			allocateAndBindUniforms<DeferredDirectionalLightUniforms*>(sizeof(DeferredDirectionalLightUniforms), cmdb, 0, 1);
+		TraditionalDeferredShadingUniforms* unis =
+			allocateAndBindUniforms<TraditionalDeferredShadingUniforms*>(sizeof(TraditionalDeferredShadingUniforms), cmdb, 0, 0);
 
 		unis->m_inputTexUvScale = info.m_gbufferTexCoordsScale;
 		unis->m_inputTexUvBias = info.m_gbufferTexCoordsBias;
 		unis->m_fbUvScale = info.m_lightbufferTexCoordsScale;
 		unis->m_fbUvBias = info.m_lightbufferTexCoordsBias;
 		unis->m_invViewProjMat = info.m_invViewProjectionMatrix;
-		unis->m_camPos = info.m_cameraPosWSpace.xyz();
+		unis->m_cameraPos = info.m_cameraPosWSpace.xyz();
 
-		unis->m_diffuseColor = info.m_directionalLight->m_diffuseColor;
-		unis->m_lightDir = info.m_directionalLight->m_direction;
-		unis->m_lightMatrix = info.m_directionalLight->m_textureMatrices[0];
-
-		unis->m_near = info.m_cameraNear;
-		unis->m_far = info.m_cameraFar;
-
-		if(info.m_directionalLight->m_shadowCascadeCount > 0)
+		if(dirLightc)
 		{
-			unis->m_effectiveShadowDistance = info.m_directionalLight->m_shadowCascadesDistances[info.m_directionalLight->m_shadowCascadeCount - 1];
+			unis->m_dirLight.m_diffuseColor = dirLightc->getDiffuseColor().xyz();
+			unis->m_dirLight.m_active = 1;
+			unis->m_dirLight.m_direction = dirLightc->getDirection();
+			ANKI_ASSERT(info.m_effectiveShadowDistance > 0.0f);
+			unis->m_dirLight.m_effectiveShadowDistance = info.m_effectiveShadowDistance;
+			unis->m_dirLight.m_lightMatrix = info.m_dirLightMatrix;
 		}
 		else
 		{
-			unis->m_effectiveShadowDistance = 0.0f;
+			unis->m_dirLight.m_active = 0;
 		}
 
-		drawQuad(cmdb);
-	}
-
-	// Set other light state
-	cmdb.setCullMode(FaceSelectionBit::kFront);
-
-	// Do point lights
-	U32 indexCount;
-	bindVertexIndexBuffers(ProxyType::kProxySphere, cmdb, indexCount);
-	cmdb.bindShaderProgram(m_plightGrProg[info.m_computeSpecular].get());
-
-	for(const PointLightQueueElement& plightEl : info.m_pointLights)
-	{
-		// Update uniforms
-		DeferredVertexUniforms* vert = allocateAndBindUniforms<DeferredVertexUniforms*>(sizeof(DeferredVertexUniforms), cmdb, 0, 0);
-
-		Mat4 modelM(plightEl.m_worldPosition.xyz1(), Mat3::getIdentity(), plightEl.m_radius);
-
-		vert->m_mvp = info.m_viewProjectionMatrix * modelM;
+		cmdb.bindStorageBuffer(0, 1, info.m_visibleLightsBuffer.m_buffer, info.m_visibleLightsBuffer.m_offset, info.m_visibleLightsBuffer.m_range);
+		cmdb.bindStorageBuffer(0, 2, &GpuSceneBuffer::getSingleton().getBuffer(),
+							   GpuSceneArrays::Light::getSingleton().getGpuSceneOffsetOfArrayBase(),
+							   GpuSceneArrays::Light::getSingleton().getElementCount() * GpuSceneArrays::Light::getSingleton().getElementSize());
 
-		DeferredPointLightUniforms* light = allocateAndBindUniforms<DeferredPointLightUniforms*>(sizeof(DeferredPointLightUniforms), cmdb, 0, 1);
-
-		light->m_inputTexUvScale = info.m_gbufferTexCoordsScale;
-		light->m_inputTexUvBias = info.m_gbufferTexCoordsBias;
-		light->m_fbUvScale = info.m_lightbufferTexCoordsScale;
-		light->m_fbUvBias = info.m_lightbufferTexCoordsBias;
-		light->m_invViewProjMat = info.m_invViewProjectionMatrix;
-		light->m_camPos = info.m_cameraPosWSpace.xyz();
-		light->m_position = plightEl.m_worldPosition;
-		light->m_oneOverSquareRadius = 1.0f / (plightEl.m_radius * plightEl.m_radius);
-		light->m_diffuseColor = plightEl.m_diffuseColor;
-
-		// Draw
-		cmdb.drawIndexed(PrimitiveTopology::kTriangles, indexCount);
-	}
-
-	// Do spot lights
-	bindVertexIndexBuffers(ProxyType::kProxyCone, cmdb, indexCount);
-	cmdb.bindShaderProgram(m_slightGrProg[info.m_computeSpecular].get());
-
-	for(const SpotLightQueueElement& splightEl : info.m_spotLights)
-	{
-		// Compute the model matrix
-		//
-		Mat4 modelM(splightEl.m_worldTransform.getTranslationPart().xyz1(), splightEl.m_worldTransform.getRotationPart(), 1.0f);
-
-		// Calc the scale of the cone
-		Mat4 scaleM(Mat4::getIdentity());
-		scaleM(0, 0) = tan(splightEl.m_outerAngle / 2.0f) * splightEl.m_distance;
-		scaleM(1, 1) = scaleM(0, 0);
-		scaleM(2, 2) = splightEl.m_distance;
-
-		modelM = modelM * scaleM;
-
-		// Update vertex uniforms
-		DeferredVertexUniforms* vert = allocateAndBindUniforms<DeferredVertexUniforms*>(sizeof(DeferredVertexUniforms), cmdb, 0, 0);
-		vert->m_mvp = info.m_viewProjectionMatrix * modelM;
-
-		// Update fragment uniforms
-		DeferredSpotLightUniforms* light = allocateAndBindUniforms<DeferredSpotLightUniforms*>(sizeof(DeferredSpotLightUniforms), cmdb, 0, 1);
-
-		light->m_inputTexUvScale = info.m_gbufferTexCoordsScale;
-		light->m_inputTexUvBias = info.m_gbufferTexCoordsBias;
-		light->m_fbUvScale = info.m_lightbufferTexCoordsScale;
-		light->m_fbUvBias = info.m_lightbufferTexCoordsBias;
-		light->m_invViewProjMat = info.m_invViewProjectionMatrix;
-		light->m_camPos = info.m_cameraPosWSpace.xyz();
+		// NOTE: Use nearest sampler because we don't want the result to sample the near tiles
+		cmdb.bindSampler(0, 3, getRenderer().getSamplers().m_nearestNearestClamp.get());
 
-		light->m_position = splightEl.m_worldTransform.getTranslationPart().xyz();
-		light->m_oneOverSquareRadius = 1.0f / (splightEl.m_distance * splightEl.m_distance);
+		rgraphCtx.bindColorTexture(0, 4, info.m_gbufferRenderTargets[0]);
+		rgraphCtx.bindColorTexture(0, 5, info.m_gbufferRenderTargets[1]);
+		rgraphCtx.bindColorTexture(0, 6, info.m_gbufferRenderTargets[2]);
+		rgraphCtx.bindTexture(0, 7, info.m_gbufferDepthRenderTarget, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
 
-		light->m_diffuseColor = splightEl.m_diffuseColor;
-		light->m_outerCos = cos(splightEl.m_outerAngle / 2.0f);
+		cmdb.bindSampler(0, 8, m_shadowSampler.get());
+		if(dirLightc && dirLightc->getShadowEnabled())
+		{
+			ANKI_ASSERT(info.m_directionalLightShadowmapRenderTarget.isValid());
+			rgraphCtx.bindTexture(0, 9, info.m_directionalLightShadowmapRenderTarget, TextureSubresourceInfo(DepthStencilAspectBit::kDepth));
+		}
+		else
+		{
+			// No shadows for the dir light, bind something random
+			rgraphCtx.bindColorTexture(0, 9, info.m_gbufferRenderTargets[0]);
+		}
 
-		light->m_lightDir = -splightEl.m_worldTransform.getZAxis().xyz();
-		light->m_innerCos = cos(splightEl.m_innerAngle / 2.0f);
+		cmdb.bindShaderProgram(m_lightGrProg[info.m_computeSpecular].get());
 
-		// Draw
-		cmdb.drawIndexed(PrimitiveTopology::kTriangles, indexCount);
+		drawQuad(cmdb);
 	}
-
-	// Restore state
-	cmdb.setBlendFactors(0, BlendFactor::kOne, BlendFactor::kZero);
-	cmdb.setCullMode(FaceSelectionBit::kBack);
 }
 
 } // end namespace anki

+ 7 - 27
AnKi/Renderer/Utils/TraditionalDeferredShading.h

@@ -25,13 +25,11 @@ public:
 	Vec2 m_gbufferTexCoordsBias;
 	Vec2 m_lightbufferTexCoordsScale;
 	Vec2 m_lightbufferTexCoordsBias;
-	F32 m_cameraNear;
-	F32 m_cameraFar;
-	const DirectionalLightQueueElement* m_directionalLight = nullptr;
-	ConstWeakArray<PointLightQueueElement> m_pointLights;
-	ConstWeakArray<SpotLightQueueElement> m_spotLights;
-	const SkyboxQueueElement* m_skybox = nullptr;
-	CommandBuffer* m_commandBuffer = nullptr;
+	F32 m_effectiveShadowDistance = -1.0f; // TODO rm
+	Mat4 m_dirLightMatrix; // TODO rm
+
+	BufferOffsetRange m_visibleLightsBuffer;
+
 	Bool m_computeSpecular = false;
 
 	// Render targets
@@ -48,35 +46,17 @@ class TraditionalDeferredLightShading : public RendererObject
 public:
 	Error init();
 
-	/// Run the light shading. It will iterate over the lights and draw them. It doesn't bind anything related to
-	/// GBuffer or the output buffer.
+	/// Run the light shading. It will iterate over the lights and draw them. It doesn't bind anything related to GBuffer or the output buffer.
 	void drawLights(TraditionalDeferredLightShadingDrawInfo& info);
 
 private:
-	enum class ProxyType
-	{
-		kProxySphere,
-		kProxyCone
-	};
-
 	ShaderProgramResourcePtr m_lightProg;
-	Array<ShaderProgramPtr, 2> m_plightGrProg;
-	Array<ShaderProgramPtr, 2> m_slightGrProg;
-	Array<ShaderProgramPtr, 2> m_dirLightGrProg;
+	Array<ShaderProgramPtr, 2> m_lightGrProg;
 
 	ShaderProgramResourcePtr m_skyboxProg;
 	Array<ShaderProgramPtr, 2> m_skyboxGrProgs;
 
-	/// @name Meshes of light volumes.
-	/// @{
-	BufferPtr m_proxyVolumesBuffer;
-	/// @}
-
 	SamplerPtr m_shadowSampler;
-
-	void bindVertexIndexBuffers(ProxyType proxyType, CommandBuffer& cmdb, U32& indexCount) const;
-
-	void createProxyMeshes();
 };
 /// @}
 } // end namespace anki

+ 5 - 0
AnKi/Scene/Components/LightComponent.h

@@ -117,6 +117,11 @@ public:
 		return WeakArray<Frustum>(m_frustums, m_frustumCount);
 	}
 
+	Vec3 getDirection() const
+	{
+		return -m_worldTransform.getRotation().getZAxis().xyz();
+	}
+
 	void setupPointLightQueueElement(PointLightQueueElement& el) const
 	{
 		ANKI_ASSERT(m_type == LightComponentType::kPoint);

+ 17 - 0
AnKi/Scene/Components/SkyboxComponent.h

@@ -35,14 +35,31 @@ public:
 
 	~SkyboxComponent();
 
+	SkyboxType getSkyboxType() const
+	{
+		return m_type;
+	}
+
 	void setSolidColor(const Vec3& color)
 	{
 		m_type = SkyboxType::kSolidColor;
 		m_color = color.max(Vec3(0.0f));
 	}
 
+	Vec3 getSolidColor() const
+	{
+		ANKI_ASSERT(m_type == SkyboxType::kSolidColor);
+		return m_color;
+	}
+
 	void loadImageResource(CString filename);
 
+	ImageResource& getImageResource() const
+	{
+		ANKI_ASSERT(m_type == SkyboxType::kImage2D);
+		return *m_image;
+	}
+
 	void setMinFogDensity(F32 density)
 	{
 		m_fog.m_minDensity = clamp(density, 0.0f, 100.0f);

+ 10 - 62
AnKi/Shaders/Include/TraditionalDeferredShadingTypes.h

@@ -9,54 +9,18 @@
 
 ANKI_BEGIN_NAMESPACE
 
-struct DeferredPointLightUniforms
+struct TraditionalDeferredShadingDirectionalLight
 {
-	// Use these to get the correct face UVs
-	Vec2 m_inputTexUvScale;
-	Vec2 m_inputTexUvBias;
-
-	Vec2 m_fbUvScale;
-	Vec2 m_fbUvBias;
-
-	Mat4 m_invViewProjMat;
-
-	Vec3 m_camPos;
-	F32 m_padding;
-
-	// Light props
-	Vec3 m_position;
-	F32 m_oneOverSquareRadius; // 1/radius^2
-
 	Vec3 m_diffuseColor;
-	F32 m_padding2;
-};
+	U32 m_active;
 
-struct DeferredSpotLightUniforms
-{
-	// Use these to get the correct face UVs
-	Vec2 m_inputTexUvScale;
-	Vec2 m_inputTexUvBias;
-
-	Vec2 m_fbUvScale;
-	Vec2 m_fbUvBias;
-
-	Mat4 m_invViewProjMat;
-
-	Vec3 m_camPos;
-	F32 m_padding;
-
-	// Light props
-	Vec3 m_position;
-	F32 m_oneOverSquareRadius; // 1/radius^2
-
-	Vec3 m_diffuseColor;
-	F32 m_outerCos;
+	Vec3 m_direction;
+	F32 m_effectiveShadowDistance;
 
-	Vec3 m_lightDir;
-	F32 m_innerCos;
+	Mat4 m_lightMatrix;
 };
 
-struct DeferredDirectionalLightUniforms
+struct TraditionalDeferredShadingUniforms
 {
 	// Use these to get the correct face UVs
 	Vec2 m_inputTexUvScale;
@@ -67,31 +31,15 @@ struct DeferredDirectionalLightUniforms
 
 	Mat4 m_invViewProjMat;
 
-	Vec3 m_camPos;
-	F32 m_near;
-
-	// Light props
-	Vec3 m_diffuseColor;
-	F32 m_far;
-
-	Vec3 m_lightDir;
-	F32 m_effectiveShadowDistance;
-
-	Mat4 m_lightMatrix;
-};
+	Vec3 m_cameraPos;
+	F32 m_padding0;
 
-struct DeferredVertexUniforms
-{
-	Mat4 m_mvp;
+	TraditionalDeferredShadingDirectionalLight m_dirLight;
 };
 
-struct DeferredSkyboxUniforms
+struct TraditionalDeferredSkyboxUniforms
 {
-#if ANKI_GLSL
-	ANKI_RP Vec3 m_solidColor;
-#else
 	RVec3 m_solidColor;
-#endif
 	F32 m_padding1;
 
 	Vec2 m_inputTexUvScale;

+ 61 - 78
AnKi/Shaders/TraditionalDeferredShading.ankiprog

@@ -5,32 +5,18 @@
 
 // Classic deferred lighting shader
 
-#pragma anki mutator LIGHT_TYPE 0 1 2
 #pragma anki mutator SPECULAR 0 1
 
-#define POINT_LIGHT_TYPE 0
-#define SPOT_LIGHT_TYPE 1
-#define DIR_LIGHT_TYPE 2
-
 // VERT
 #pragma anki start vert
 #include <AnKi/Shaders/Common.hlsl>
 
-#if LIGHT_TYPE == DIR_LIGHT_TYPE
 Vec4 main(U32 svVertexId : SV_VERTEXID) : SV_POSITION
 {
 	const Vec2 uv = Vec2(svVertexId & 1, svVertexId >> 1) * 2.0;
 	const Vec2 pos = uv * 2.0 - 1.0;
 	return Vec4(pos, 0.0, 1.0);
 }
-#else
-[[vk::binding(0)]] ConstantBuffer<Mat4> g_mvp;
-
-Vec4 main([[vk::location(0)]] Vec3 position : POSITION) : SV_POSITION
-{
-	return mul(g_mvp, Vec4(position, 1.0));
-}
-#endif
 #pragma anki end
 
 // FRAG
@@ -38,30 +24,22 @@ Vec4 main([[vk::location(0)]] Vec3 position : POSITION) : SV_POSITION
 #include <AnKi/Shaders/PackFunctions.hlsl>
 #include <AnKi/Shaders/LightFunctions.hlsl>
 #include <AnKi/Shaders/Include/TraditionalDeferredShadingTypes.h>
+#include <AnKi/Shaders/Include/GpuSceneTypes.h>
 
-[[vk::binding(1)]] ConstantBuffer<
-#if LIGHT_TYPE == POINT_LIGHT_TYPE
-	DeferredPointLightUniforms
-#elif LIGHT_TYPE == SPOT_LIGHT_TYPE
-	DeferredSpotLightUniforms
-#elif LIGHT_TYPE == DIR_LIGHT_TYPE
-	DeferredDirectionalLightUniforms
-#else
-#	error See file
-#endif
-	>
-	g_unis;
-
-[[vk::binding(2)]] SamplerState g_gbufferSampler;
-[[vk::binding(3)]] Texture2D<Vec4> g_gbufferTex0;
-[[vk::binding(4)]] Texture2D<Vec4> g_gbufferTex1;
-[[vk::binding(5)]] Texture2D<Vec4> g_gbufferTex2;
-[[vk::binding(6)]] Texture2D g_depthTex;
-
-#if LIGHT_TYPE == DIR_LIGHT_TYPE
-[[vk::binding(7)]] SamplerComparisonState g_shadowMapSampler;
-[[vk::binding(8)]] Texture2D<RVec4> g_shadowMap;
-#endif
+[[vk::binding(0)]] ConstantBuffer<TraditionalDeferredShadingUniforms> g_unis;
+
+[[vk::binding(1)]] StructuredBuffer<U32> g_visibleLightIds;
+[[vk::binding(2)]] StructuredBuffer<GpuSceneLight> g_lights;
+
+[[vk::binding(3)]] SamplerState g_gbufferSampler;
+[[vk::binding(4)]] Texture2D<Vec4> g_gbufferTex0;
+[[vk::binding(5)]] Texture2D<Vec4> g_gbufferTex1;
+[[vk::binding(6)]] Texture2D<Vec4> g_gbufferTex2;
+[[vk::binding(7)]] Texture2D<Vec4> g_depthTex;
+
+// For directional light:
+[[vk::binding(8)]] SamplerComparisonState g_shadowMapSampler;
+[[vk::binding(9)]] Texture2D<RVec4> g_shadowMap;
 
 RVec3 main(Vec4 svPosition : SV_POSITION) : SV_TARGET0
 {
@@ -70,14 +48,10 @@ RVec3 main(Vec4 svPosition : SV_POSITION) : SV_TARGET0
 	const Vec2 uvToWrite = mad(Vec2(svPosition.xy), g_unis.m_fbUvScale, g_unis.m_fbUvBias);
 
 	const F32 depth = g_depthTex.SampleLevel(g_gbufferSampler, uvToRead, 0.0).r;
-
-#if LIGHT_TYPE != DIR_LIGHT_TYPE
-	// Do manual depth test
-	if(svPosition.z < depth)
+	if(depth == 1.0f)
 	{
 		discard;
 	}
-#endif
 
 	// Decode and process gbuffer
 	GbufferInfo gbuffer = (GbufferInfo)0;
@@ -91,52 +65,61 @@ RVec3 main(Vec4 svPosition : SV_POSITION) : SV_TARGET0
 	// Compute diff
 	const Vec3 diffC = diffuseLobe(gbuffer.m_diffuse);
 
-	// Compute spec
-#if LIGHT_TYPE == DIR_LIGHT_TYPE
-	const Vec3 l = -g_unis.m_lightDir;
-#else
-	const Vec3 frag2Light = g_unis.m_position - worldPos;
-	const Vec3 l = normalize(frag2Light);
-	const RF32 nol = max(0.0, dot(gbuffer.m_normal, l));
-#endif
+	Vec3 outColor = gbuffer.m_emission;
+	const Vec3 viewDir = normalize(g_unis.m_cameraPos - worldPos);
+	ANKI_MAYBE_UNUSED(viewDir);
+
+	// Dir light
+	if(g_unis.m_dirLight.m_active)
+	{
+		const F32 dist = length(g_unis.m_cameraPos - worldPos);
+		RF32 shadowFactor;
+		if(dist < g_unis.m_dirLight.m_effectiveShadowDistance)
+		{
+			// Acceptable distance
+
+			shadowFactor = computeShadowFactorDirLight(g_unis.m_dirLight.m_lightMatrix, worldPos, g_shadowMap, g_shadowMapSampler);
+		}
+		else
+		{
+			shadowFactor = 1.0;
+		}
+
+		const Vec3 l = -g_unis.m_dirLight.m_direction;
+		const RF32 lambert = dot(l, gbuffer.m_normal);
+		const RF32 factor = shadowFactor * max(gbuffer.m_subsurface, lambert);
 
 #if SPECULAR == 1
-	const Vec3 viewDir = normalize(g_unis.m_camPos - worldPos);
-	const Vec3 specC = specularIsotropicLobe(gbuffer, viewDir, l);
+		const Vec3 specC = specularIsotropicLobe(gbuffer, viewDir, l);
 #else
-	const Vec3 specC = Vec3(0.0, 0.0, 0.0);
+		const Vec3 specC = Vec3(0.0, 0.0, 0.0);
 #endif
+		outColor += (specC + diffC) * g_unis.m_dirLight.m_diffuseColor * factor;
+	}
 
-	// Compute factors
-#if LIGHT_TYPE == POINT_LIGHT_TYPE
-	const RF32 att = computeAttenuationFactor(g_unis.m_oneOverSquareRadius, frag2Light);
-	const RF32 lambert = nol;
-	const RF32 factor = att * max(lambert, gbuffer.m_subsurface);
-#elif LIGHT_TYPE == SPOT_LIGHT_TYPE
-	const RF32 att = computeAttenuationFactor(g_unis.m_oneOverSquareRadius, frag2Light);
-	const RF32 lambert = nol;
-	const RF32 spot = computeSpotFactor(l, g_unis.m_outerCos, g_unis.m_innerCos, g_unis.m_lightDir);
-	const RF32 factor = att * spot * max(lambert, gbuffer.m_subsurface);
-#else
-	const F32 linearDepth = linearizeDepth(depth, g_unis.m_near, g_unis.m_far);
-	RF32 shadowFactor;
-	if(linearDepth * (g_unis.m_far - g_unis.m_near) < g_unis.m_effectiveShadowDistance)
+	// For all (other) lights
+	const U32 lightCount = g_visibleLightIds[0];
+	for(U32 i = 1; i <= lightCount; ++i)
 	{
-		// Acceptable distance
+		const GpuSceneLight light = g_lights[g_visibleLightIds[i]];
 
-		shadowFactor = computeShadowFactorDirLight(g_unis.m_lightMatrix, worldPos, g_shadowMap, g_shadowMapSampler);
-	}
-	else
-	{
-		shadowFactor = 1.0;
-	}
+		const Vec3 frag2Light = light.m_position - worldPos;
+		const Vec3 l = normalize(frag2Light);
+		const F32 nol = max(0.0, dot(gbuffer.m_normal, l));
+
+		const F32 att = computeAttenuationFactor(1.0f / (light.m_radius * light.m_radius), frag2Light);
+		const F32 lambert = nol;
+		const F32 spot = (light.m_type == 1) ? computeSpotFactor(l, light.m_outerCos, light.m_innerCos, light.m_direction) : 1.0f;
+		const F32 factor = att * spot * max(lambert, gbuffer.m_subsurface);
 
-	const RF32 lambert = dot(l, gbuffer.m_normal);
-	const RF32 factor = shadowFactor * max(gbuffer.m_subsurface, lambert);
+#if SPECULAR == 1
+		const Vec3 specC = specularIsotropicLobe(gbuffer, viewDir, l);
+#else
+		const Vec3 specC = Vec3(0.0, 0.0, 0.0);
 #endif
 
-	RVec3 outColor = gbuffer.m_emission;
-	outColor += (specC + diffC) * g_unis.m_diffuseColor * factor;
+		outColor += (specC + diffC) * light.m_diffuseColor * factor;
+	}
 
 	return outColor;
 }

+ 2 - 2
AnKi/Shaders/TraditionalDeferredShadingSkybox.ankiprog

@@ -14,7 +14,7 @@
 #include <AnKi/Shaders/Functions.hlsl>
 #include <AnKi/Shaders/Include/TraditionalDeferredShadingTypes.h>
 
-[[vk::push_constant]] ConstantBuffer<DeferredSkyboxUniforms> g_unis;
+[[vk::push_constant]] ConstantBuffer<TraditionalDeferredSkyboxUniforms> g_unis;
 
 [[vk::binding(0)]] SamplerState g_nearestAnyClampSampler;
 [[vk::binding(1)]] Texture2D g_depthTex;
@@ -29,7 +29,7 @@ RVec3 main(Vec2 uv : TEXCOORD, Vec4 svPosition : SV_POSITION) : SV_TARGET0
 	const Vec2 uvToRead = mad(svPosition.xy, g_unis.m_inputTexUvScale, g_unis.m_inputTexUvBias);
 
 	const F32 depth = g_depthTex.SampleLevel(g_nearestAnyClampSampler, uvToRead, 0.0).r;
-	if(depth != 1.0)
+	if(depth != 1.0f)
 	{
 		discard;
 	}