Browse Source

Merge the light types into one array. Have the shader decide the light
using an if()

Panagiotis Christopoulos Charitos 8 years ago
parent
commit
f722605565

+ 11 - 18
shaders/ClusterLightCommon.glsl

@@ -21,25 +21,23 @@ struct LightingUniforms
 	mat4 invProjMat;
 };
 
-// Point light
-struct PointLight
+// Point or spot light
+struct Light
 {
 	vec4 posRadius; // xyz: Light pos in view space. w: The -1/(radius^2)
 	vec4 diffuseColorShadowmapId; // xyz: diff color, w: shadowmap tex ID
 	vec4 specularColorRadius; // xyz: spec color, w: radius
-};
 
-// Spot light
-struct SpotLight
-{
-	vec4 posRadius; // xyz: Light pos in view space. w: The -1/(radius^2)
-	vec4 diffuseColorShadowmapId; // xyz: diff color, w: shadowmap tex ID
-	vec4 specularColorRadius; // xyz: spec color, w: radius
 	vec4 lightDir;
 	vec4 outerCosInnerCos;
 	mat4 texProjectionMat;
 };
 
+bool isSpotLight(in Light l)
+{
+	return l.outerCosInnerCos.x != 0.0;
+}
+
 // Representation of a reflection probe
 struct ReflectionProbe
 {
@@ -97,25 +95,20 @@ layout(ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING), std140, row_major) unifor
 
 #ifdef FRAGMENT_SHADER
 
-layout(ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING + 1), std140) uniform u1_
-{
-	PointLight u_pointLights[UBO_MAX_SIZE / (3 * 4 * 4)];
-};
-
-layout(ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING + 2), std140, row_major) uniform u2_
+layout(ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING + 1), std140, row_major) uniform u1_
 {
-	SpotLight u_spotLights[UBO_MAX_SIZE / (9 * 4 * 4)];
+	Light u_lights[UBO_MAX_SIZE / (9 * 4 * 4)];
 };
 
 #ifdef LIGHT_INDIRECT
-layout(std140, row_major, ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING + 3)) uniform u3_
+layout(std140, row_major, ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING + 2)) uniform u2_
 {
 	ReflectionProbe u_reflectionProbes[UBO_MAX_SIZE / (2 * 4 * 4)];
 };
 #endif
 
 #ifdef LIGHT_DECALS
-layout(std140, row_major, ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING + 4)) uniform u4_
+layout(std140, row_major, ANKI_UBO_BINDING(LIGHT_SET, LIGHT_UBO_BINDING + 3)) uniform u3_
 {
 	Decal u_decals[UBO_MAX_SIZE / ((4 + 16) * 4)];
 };

+ 25 - 37
shaders/FsCommonFrag.glsl

@@ -130,59 +130,47 @@ vec3 computeLightColor(vec3 diffCol)
 	uint count = u_lightIndices[idxOffset];
 	idxOffset += count + 1;
 
-	// Point lights
+	// Lights
 	count = u_lightIndices[idxOffset++];
 	while(count-- != 0)
 	{
-		PointLight light = u_pointLights[u_lightIndices[idxOffset++]];
+		Light light = u_lights[u_lightIndices[idxOffset++]];
 
 		vec3 diffC = computeDiffuseColor(diffCol, light.diffuseColorShadowmapId.rgb);
 
 		vec3 frag2Light = light.posRadius.xyz - fragPos;
-		float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
+		float factor = computeAttenuationFactor(light.posRadius.w, frag2Light);
 
 #if LOD > 1
-		const float shadow = 1.0;
-#else
-		float shadow = 1.0;
-		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
-		if(light.diffuseColorShadowmapId.w >= 0.0)
+		if(isSpotLight(light))
 		{
-			shadow = computeShadowFactorOmni(
-				frag2Light, shadowmapLayerIdx, light.specularColorRadius.w, u_invViewRotation, u_omniMapArr);
+			vec3 l = normalize(frag2Light);
+			factor *= computeSpotFactor(l, light.outerCosInnerCos.x, light.outerCosInnerCos.y, light.lightDir.xyz);
 		}
-#endif
-
-		outColor += diffC * (att * shadow);
-	}
-
-	// Spot lights
-	count = u_lightIndices[idxOffset++];
-	while(count-- != 0)
-	{
-		SpotLight light = u_spotLights[u_lightIndices[idxOffset++]];
-
-		vec3 diffC = computeDiffuseColor(diffCol, light.diffuseColorShadowmapId.rgb);
-
-		vec3 frag2Light = light.posRadius.xyz - fragPos;
-		float att = computeAttenuationFactor(light.posRadius.w, frag2Light);
-
-		vec3 l = normalize(frag2Light);
-
-		float spot = computeSpotFactor(l, light.outerCosInnerCos.x, light.outerCosInnerCos.y, light.lightDir.xyz);
-
-#if LOD > 1
-		const float shadow = 1.0;
 #else
-		float shadow = 1.0;
-		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
-		if(shadowmapLayerIdx >= 0.0)
+		if(isSpotLight(light))
+		{
+			vec3 l = normalize(frag2Light);
+			factor *= computeSpotFactor(l, light.outerCosInnerCos.x, light.outerCosInnerCos.y, light.lightDir.xyz);
+
+			float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
+			if(shadowmapLayerIdx >= 0.0)
+			{
+				factor *= computeShadowFactorSpot(light.texProjectionMat, fragPos, shadowmapLayerIdx, 1, u_spotMapArr);
+			}
+		}
+		else
 		{
-			shadow = computeShadowFactorSpot(light.texProjectionMat, fragPos, shadowmapLayerIdx, 1, u_spotMapArr);
+			float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
+			if(light.diffuseColorShadowmapId.w >= 0.0)
+			{
+				factor *= computeShadowFactorOmni(
+					frag2Light, shadowmapLayerIdx, light.specularColorRadius.w, u_invViewRotation, u_omniMapArr);
+			}
 		}
 #endif
 
-		outColor += diffC * (att * spot * shadow);
+		outColor += diffC * factor;
 	}
 
 	return outColor;

+ 20 - 26
shaders/Is.frag.glsl

@@ -180,44 +180,38 @@ void main()
 	// Ambient and emissive color
 	vec3 outC = diffCol * emission;
 
-	// Point lights
+	// Lights
 	count = u_lightIndices[idxOffset++];
 	while(count-- != 0)
 	{
-		PointLight light = u_pointLights[u_lightIndices[idxOffset++]];
+		Light light = u_lights[u_lightIndices[idxOffset++]];
 
 		LIGHTING_COMMON_BRDF();
 
 		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
-		if(light.diffuseColorShadowmapId.w >= 0.0)
+		if(isSpotLight(light))
 		{
-			float shadow = computeShadowFactorOmni(
-				frag2Light, shadowmapLayerIdx, light.specularColorRadius.w, u_invViewRotation, u_omniMapArr);
-			lambert *= shadow;
+			float spot = computeSpotFactor(l, light.outerCosInnerCos.x, light.outerCosInnerCos.y, light.lightDir.xyz);
+			att *= spot;
+
+			if(shadowmapLayerIdx >= 0.0)
+			{
+				float shadow = computeShadowFactorSpot(
+					light.texProjectionMat, fragPos, shadowmapLayerIdx, shadowSampleCount, u_spotMapArr);
+				lambert *= shadow;
+			}
 		}
-
-		outC += (specC + diffC) * (att * max(subsurface, lambert));
-	}
-
-	// Spot lights
-	count = u_lightIndices[idxOffset++];
-	while(count-- != 0)
-	{
-		SpotLight light = u_spotLights[u_lightIndices[idxOffset++]];
-
-		LIGHTING_COMMON_BRDF();
-
-		float spot = computeSpotFactor(l, light.outerCosInnerCos.x, light.outerCosInnerCos.y, light.lightDir.xyz);
-
-		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
-		if(shadowmapLayerIdx >= 0.0)
+		else
 		{
-			float shadow = computeShadowFactorSpot(
-				light.texProjectionMat, fragPos, shadowmapLayerIdx, shadowSampleCount, u_spotMapArr);
-			lambert *= shadow;
+			if(light.diffuseColorShadowmapId.w >= 0.0)
+			{
+				float shadow = computeShadowFactorOmni(
+					frag2Light, shadowmapLayerIdx, light.specularColorRadius.w, u_invViewRotation, u_omniMapArr);
+				lambert *= shadow;
+			}
 		}
 
-		outC += (diffC + specC) * (att * spot * max(subsurface, lambert));
+		outC += (specC + diffC) * (att * max(subsurface, lambert));
 	}
 
 #if INDIRECT_ENABLED

+ 27 - 37
shaders/Volumetric.frag.glsl

@@ -19,7 +19,7 @@ layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_msDepthRt;
 layout(ANKI_TEX_BINDING(0, 1)) uniform sampler2DArray u_noiseTex;
 layout(ANKI_TEX_BINDING(0, 2)) uniform sampler2D u_historyRt;
 
-layout(std140, ANKI_UBO_BINDING(0, 3), row_major) uniform ubo0_
+layout(std140, ANKI_UBO_BINDING(0, 2), row_major) uniform u2_
 {
 	vec4 u_linearizeNoiseTexOffsetLayer;
 	vec4 u_fogParticleColorPad1;
@@ -38,47 +38,41 @@ const uint MAX_SAMPLES_PER_CLUSTER = 4u;
 const float DIST_BETWEEN_SAMPLES = 0.25;
 
 // Return the diffuse color without taking into account the diffuse term of the particles.
-vec3 computeLightColor(vec3 fragPos, uint plightCount, uint plightIdx, uint slightCount, uint slightIdx)
+vec3 computeLightColor(vec3 fragPos, uint lightCount, uint lightIdx)
 {
 	vec3 outColor = vec3(0.0);
 
-	// Point lights
-	while(plightCount-- != 0)
+	// All lights
+	while(lightCount-- != 0)
 	{
-		PointLight light = u_pointLights[u_lightIndices[plightIdx++]];
+		Light light = u_lights[u_lightIndices[lightIdx++]];
 		vec3 frag2Light = light.posRadius.xyz - fragPos;
 		float factor = computeAttenuationFactor(light.posRadius.w, frag2Light);
 
-#if ENABLE_SHADOWS
-		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
-		if(light.diffuseColorShadowmapId.w >= 0.0)
+		if(isSpotLight(light))
 		{
-			factor *= computeShadowFactorOmni(
-				frag2Light, shadowmapLayerIdx, -1.0 / light.posRadius.w, u_invViewRotation, u_omniMapArr);
-		}
-#endif
-
-		outColor += light.diffuseColorShadowmapId.rgb * factor;
-	}
-
-	// Spot lights
-	while(slightCount-- != 0)
-	{
-		SpotLight light = u_spotLights[u_lightIndices[slightIdx++]];
-		vec3 frag2Light = light.posRadius.xyz - fragPos;
-		float factor = computeAttenuationFactor(light.posRadius.w, frag2Light);
-
-		vec3 l = normalize(frag2Light);
-
-		factor *= computeSpotFactor(l, light.outerCosInnerCos.x, light.outerCosInnerCos.y, light.lightDir.xyz);
+			vec3 l = normalize(frag2Light);
+			factor *= computeSpotFactor(l, light.outerCosInnerCos.x, light.outerCosInnerCos.y, light.lightDir.xyz);
 
 #if ENABLE_SHADOWS
-		float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
-		if(shadowmapLayerIdx >= 0.0)
-		{
-			factor *= computeShadowFactorSpot(light.texProjectionMat, fragPos, shadowmapLayerIdx, 1, u_spotMapArr);
+			float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
+			if(shadowmapLayerIdx >= 0.0)
+			{
+				factor *= computeShadowFactorSpot(light.texProjectionMat, fragPos, shadowmapLayerIdx, 1, u_spotMapArr);
+			}
+#endif
 		}
+		else
+		{
+#if ENABLE_SHADOWS
+			float shadowmapLayerIdx = light.diffuseColorShadowmapId.w;
+			if(light.diffuseColorShadowmapId.w >= 0.0)
+			{
+				factor *= computeShadowFactorOmni(
+					frag2Light, shadowmapLayerIdx, -1.0 / light.posRadius.w, u_invViewRotation, u_omniMapArr);
+			}
 #endif
+		}
 
 		outColor += light.diffuseColorShadowmapId.rgb * factor;
 	}
@@ -132,12 +126,8 @@ void main()
 		uint count = u_lightIndices[idxOffset];
 		idxOffset += count + 1;
 
-		uint plightCount = u_lightIndices[idxOffset++];
-		uint plightIdx = idxOffset;
-		idxOffset += plightCount;
-
-		uint slightCount = u_lightIndices[idxOffset++];
-		uint slightIdx = idxOffset;
+		uint lightCount = u_lightIndices[idxOffset];
+		uint lightIdx = idxOffset + 1;
 
 		for(float factor = start; factor <= 1.0; factor += dist)
 		{
@@ -151,7 +141,7 @@ void main()
 
 			vec3 fragPos = viewDir * (zMedian / viewDir.z);
 
-			newCol += computeLightColor(fragPos, plightCount, plightIdx, slightCount, slightIdx);
+			newCol += computeLightColor(fragPos, lightCount, lightIdx);
 		}
 
 		kNear = kFar;

+ 1 - 2
src/anki/renderer/Fs.cpp

@@ -141,8 +141,7 @@ Error Fs::buildCommandBuffers(RenderingContext& ctx, U threadId, U threadCount)
 	cmdb->bindTexture(1, 1, m_r->getSm().m_spotTexArray);
 	cmdb->bindTexture(1, 2, m_r->getSm().m_omniTexArray);
 	bindUniforms(cmdb, 1, 0, ctx.m_is.m_commonToken);
-	bindUniforms(cmdb, 1, 1, ctx.m_is.m_pointLightsToken);
-	bindUniforms(cmdb, 1, 2, ctx.m_is.m_spotLightsToken);
+	bindUniforms(cmdb, 1, 1, ctx.m_is.m_lightsToken);
 	bindStorage(cmdb, 1, 0, ctx.m_is.m_clustersToken);
 	bindStorage(cmdb, 1, 1, ctx.m_is.m_lightIndicesToken);
 

+ 4 - 6
src/anki/renderer/Is.cpp

@@ -152,8 +152,7 @@ Error Is::binLights(RenderingContext& ctx)
 		getFrameAllocator(),
 		m_maxLightIds,
 		true,
-		ctx.m_is.m_pointLightsToken,
-		ctx.m_is.m_spotLightsToken,
+		ctx.m_is.m_lightsToken,
 		&ctx.m_is.m_probesToken,
 		ctx.m_is.m_decalsToken,
 		ctx.m_is.m_clustersToken,
@@ -189,10 +188,9 @@ void Is::run(RenderingContext& ctx)
 	cmdb->bindTexture(1, 2, m_r->getSsao().m_main.m_rt);
 
 	bindUniforms(cmdb, 0, 0, ctx.m_is.m_commonToken);
-	bindUniforms(cmdb, 0, 1, ctx.m_is.m_pointLightsToken);
-	bindUniforms(cmdb, 0, 2, ctx.m_is.m_spotLightsToken);
-	bindUniforms(cmdb, 0, 3, ctx.m_is.m_probesToken);
-	bindUniforms(cmdb, 0, 4, ctx.m_is.m_decalsToken);
+	bindUniforms(cmdb, 0, 1, ctx.m_is.m_lightsToken);
+	bindUniforms(cmdb, 0, 2, ctx.m_is.m_probesToken);
+	bindUniforms(cmdb, 0, 3, ctx.m_is.m_decalsToken);
 
 	bindStorage(cmdb, 0, 0, ctx.m_is.m_clustersToken);
 	bindStorage(cmdb, 0, 1, ctx.m_is.m_lightIndicesToken);

+ 70 - 104
src/anki/renderer/LightBin.cpp

@@ -17,7 +17,7 @@ namespace anki
 {
 
 /// This should be the number of light types. For now it's spots & points & probes & decals.
-const U SIZE_IDX_COUNT = 4;
+const U SIZE_IDX_COUNT = 3;
 
 // Shader structs and block representations. All positions and directions in viewspace
 // For documentation see the shaders
@@ -34,15 +34,7 @@ public:
 	Vec4 m_posRadius;
 	Vec4 m_diffuseColorShadowmapId;
 	Vec4 m_specularColorRadius;
-};
-
-class ShaderPointLight : public ShaderLight
-{
-};
 
-class ShaderSpotLight : public ShaderLight
-{
-public:
 	Vec4 m_lightDir;
 	Vec4 m_outerCosInnerCos;
 	Mat4 m_texProjectionMat; ///< Texture projection matrix
@@ -77,6 +69,7 @@ static const U MAX_PROBES_PER_CLUSTER = 12;
 static const U MAX_DECALS_PER_CLUSTER = 8;
 static const F32 INVALID_TEXTURE_INDEX = -1.0;
 
+/// WARNING: Keep it as small as possible, that's why the members are U16
 class ClusterLightIndex
 {
 public:
@@ -87,16 +80,27 @@ public:
 
 	U getIndex() const
 	{
-		return m_index;
+		return m_index & ~SPOT_BIT;
 	}
 
 	void setIndex(U i)
 	{
-		ANKI_ASSERT(i <= MAX_U16);
+		ANKI_ASSERT(i < MAX_U16 && !(i & SPOT_BIT));
 		m_index = i;
 	}
 
+	void setSpot(Bool spot)
+	{
+		m_index = (spot) ? (m_index | SPOT_BIT) : (m_index & ~SPOT_BIT);
+	}
+
+	Bool isSpot() const
+	{
+		return m_index & SPOT_BIT;
+	}
+
 private:
+	static const U16 SPOT_BIT = 1 << 15;
 	U16 m_index;
 };
 
@@ -154,13 +158,11 @@ static_assert(sizeof(ClusterProbeIndex) == sizeof(U16) * 2, "Because we memcmp")
 class alignas(U32) ClusterData
 {
 public:
-	Atomic<U8> m_pointCount;
-	Atomic<U8> m_spotCount;
+	Atomic<U8> m_lightCount;
 	Atomic<U8> m_probeCount;
 	Atomic<U8> m_decalCount;
 
-	Array<ClusterLightIndex, MAX_TYPED_LIGHTS_PER_CLUSTER> m_pointIds;
-	Array<ClusterLightIndex, MAX_TYPED_LIGHTS_PER_CLUSTER> m_spotIds;
+	Array<ClusterLightIndex, MAX_TYPED_LIGHTS_PER_CLUSTER> m_lightIds;
 	Array<ClusterProbeIndex, MAX_PROBES_PER_CLUSTER> m_probeIds;
 	Array<ClusterLightIndex, MAX_DECALS_PER_CLUSTER> m_decalIds;
 
@@ -171,30 +173,24 @@ public:
 
 	void reset()
 	{
-		// Set the counts to zero and try to be faster
-		*reinterpret_cast<U32*>(&m_pointCount) = 0;
+		m_lightCount.set(0);
+		m_probeCount.set(0);
+		m_decalCount.set(0);
 	}
 
 	void normalizeCounts()
 	{
-		normalize(m_pointCount, MAX_TYPED_LIGHTS_PER_CLUSTER, "point lights");
-		normalize(m_spotCount, MAX_TYPED_LIGHTS_PER_CLUSTER, "spot lights");
+		normalize(m_lightCount, MAX_TYPED_LIGHTS_PER_CLUSTER, "lights");
 		normalize(m_probeCount, MAX_PROBES_PER_CLUSTER, "probes");
 		normalize(m_decalCount, MAX_DECALS_PER_CLUSTER, "decals");
 	}
 
 	void sortLightIds()
 	{
-		const U pointCount = m_pointCount.get();
-		if(pointCount > 1)
-		{
-			std::sort(&m_pointIds[0], &m_pointIds[0] + pointCount);
-		}
-
-		const U spotCount = m_spotCount.get();
-		if(spotCount > 1)
+		const U lightCount = m_lightCount.get();
+		if(lightCount > 1)
 		{
-			std::sort(&m_spotIds[0], &m_spotIds[0] + spotCount);
+			std::sort(&m_lightIds[0], &m_lightIds[0] + lightCount);
 		}
 
 		const U probeCount = m_probeCount.get();
@@ -212,32 +208,21 @@ public:
 
 	Bool operator==(const ClusterData& b) const
 	{
-		const U pointCount = m_pointCount.get();
-		const U spotCount = m_spotCount.get();
+		const U lightCount = m_lightCount.get();
 		const U probeCount = m_probeCount.get();
 		const U decalCount = m_decalCount.get();
-		const U pointCount2 = b.m_pointCount.get();
-		const U spotCount2 = b.m_spotCount.get();
+		const U lightCount2 = b.m_lightCount.get();
 		const U probeCount2 = b.m_probeCount.get();
 		const U decalCount2 = b.m_decalCount.get();
 
-		if(pointCount != pointCount2 || spotCount != spotCount2 || probeCount != probeCount2
-			|| decalCount != decalCount2)
+		if(lightCount != lightCount2 || probeCount != probeCount2 || decalCount != decalCount2)
 		{
 			return false;
 		}
 
-		if(pointCount > 0)
-		{
-			if(memcmp(&m_pointIds[0], &b.m_pointIds[0], sizeof(m_pointIds[0]) * pointCount) != 0)
-			{
-				return false;
-			}
-		}
-
-		if(spotCount > 0)
+		if(lightCount > 0)
 		{
-			if(memcmp(&m_spotIds[0], &b.m_spotIds[0], sizeof(m_spotIds[0]) * spotCount) != 0)
+			if(memcmp(&m_lightIds[0], &b.m_lightIds[0], sizeof(m_lightIds[0]) * lightCount) != 0)
 			{
 				return false;
 			}
@@ -293,16 +278,14 @@ public:
 	StackAllocator<U8> m_alloc;
 
 	// To fill the light buffers
-	WeakArray<ShaderPointLight> m_pointLights;
-	WeakArray<ShaderSpotLight> m_spotLights;
+	WeakArray<ShaderLight> m_lights;
 	WeakArray<ShaderProbe> m_probes;
 	WeakArray<ShaderDecal> m_decals;
 
 	WeakArray<U32> m_lightIds;
 	WeakArray<ShaderCluster> m_clusters;
 
-	Atomic<U32> m_pointLightsCount = {0};
-	Atomic<U32> m_spotLightsCount = {0};
+	Atomic<U32> m_lightCount = {0};
 	Atomic<U32> m_probeCount = {0};
 	Atomic<U32> m_decalCount = {0};
 
@@ -369,8 +352,7 @@ Error LightBin::bin(const Mat4& viewMat,
 	StackAllocator<U8> frameAlloc,
 	U maxLightIndices,
 	Bool shadowsEnabled,
-	StagingGpuMemoryToken& pointLightsToken,
-	StagingGpuMemoryToken& spotLightsToken,
+	StagingGpuMemoryToken& lightsToken,
 	StagingGpuMemoryToken* probesToken,
 	StagingGpuMemoryToken& decalsToken,
 	StagingGpuMemoryToken& clustersToken,
@@ -409,35 +391,31 @@ Error LightBin::bin(const Mat4& viewMat,
 	ctx.m_shadowsEnabled = shadowsEnabled;
 	ctx.m_tempClusters.create(m_clusterCount);
 
-	if(visiblePointLightsCount)
+	if(visiblePointLightsCount || visibleSpotLightsCount)
 	{
-		ShaderPointLight* data = static_cast<ShaderPointLight*>(m_stagingMem->allocateFrame(
-			sizeof(ShaderPointLight) * visiblePointLightsCount, StagingGpuMemoryType::UNIFORM, pointLightsToken));
-
-		ctx.m_pointLights = WeakArray<ShaderPointLight>(data, visiblePointLightsCount);
+		ShaderLight* data = static_cast<ShaderLight*>(
+			m_stagingMem->allocateFrame(sizeof(ShaderLight) * (visiblePointLightsCount + visibleSpotLightsCount),
+				StagingGpuMemoryType::UNIFORM,
+				lightsToken));
 
-		ctx.m_vPointLights =
-			WeakArray<const VisibleNode>(vi.getBegin(VisibilityGroupType::LIGHTS_POINT), visiblePointLightsCount);
+		ctx.m_lights = WeakArray<ShaderLight>(data, visiblePointLightsCount + visibleSpotLightsCount);
 	}
 	else
 	{
-		pointLightsToken.markUnused();
+		lightsToken.markUnused();
 	}
 
-	if(visibleSpotLightsCount)
+	if(visiblePointLightsCount)
 	{
-		ShaderSpotLight* data = static_cast<ShaderSpotLight*>(m_stagingMem->allocateFrame(
-			sizeof(ShaderSpotLight) * visibleSpotLightsCount, StagingGpuMemoryType::UNIFORM, spotLightsToken));
-
-		ctx.m_spotLights = WeakArray<ShaderSpotLight>(data, visibleSpotLightsCount);
+		ctx.m_vPointLights =
+			WeakArray<const VisibleNode>(vi.getBegin(VisibilityGroupType::LIGHTS_POINT), visiblePointLightsCount);
+	}
 
+	if(visibleSpotLightsCount)
+	{
 		ctx.m_vSpotLights =
 			WeakArray<const VisibleNode>(vi.getBegin(VisibilityGroupType::LIGHTS_SPOT), visibleSpotLightsCount);
 	}
-	else
-	{
-		spotLightsToken.markUnused();
-	}
 
 	if(probesToken)
 	{
@@ -535,8 +513,8 @@ void LightBin::binLights(U32 threadId, PtrSize threadsCount, LightBinContext& ct
 	//
 	ClustererTestResult testResult;
 	m_clusterer.initTestResults(ctx.m_alloc, testResult);
-	U lightCount = ctx.m_vPointLights.getSize() + ctx.m_vSpotLights.getSize();
-	U totalCount = lightCount + ctx.m_vProbes.getSize() + ctx.m_vDecals.getSize();
+	const U lightCount = ctx.m_vPointLights.getSize() + ctx.m_vSpotLights.getSize();
+	const U totalCount = lightCount + ctx.m_vProbes.getSize() + ctx.m_vDecals.getSize();
 
 	const U TO_BIN_COUNT = 1;
 	while((start = ctx.m_count2.fetchAdd(TO_BIN_COUNT)) < totalCount)
@@ -562,7 +540,7 @@ void LightBin::binLights(U32 threadId, PtrSize threadsCount, LightBinContext& ct
 				const FrustumComponent* frc = snode.tryGetComponent<FrustumComponent>();
 
 				I pos = writeSpotLight(light, move, frc, ctx);
-				binLight(sp, light, pos, 1, ctx, testResult);
+				binLight(sp, light, pos, ctx, testResult);
 			}
 			else if(j >= ctx.m_vDecals.getSize())
 			{
@@ -574,7 +552,7 @@ void LightBin::binLights(U32 threadId, PtrSize threadsCount, LightBinContext& ct
 				SpatialComponent& sp = snode.getComponent<SpatialComponent>();
 
 				I pos = writePointLight(light, move, ctx);
-				binLight(sp, light, pos, 0, ctx, testResult);
+				binLight(sp, light, pos, ctx, testResult);
 			}
 			else
 			{
@@ -601,14 +579,13 @@ void LightBin::binLights(U32 threadId, PtrSize threadsCount, LightBinContext& ct
 
 		for(U i = start; i < end; ++i)
 		{
-			auto& cluster = ctx.m_tempClusters[i];
+			ClusterData& cluster = ctx.m_tempClusters[i];
 			cluster.normalizeCounts();
 
-			const U countP = cluster.m_pointCount.get();
-			const U countS = cluster.m_spotCount.get();
+			const U countL = cluster.m_lightCount.get();
 			const U countProbe = cluster.m_probeCount.get();
 			const U countDecal = cluster.m_decalCount.get();
-			const U count = countP + countS + countProbe + countDecal;
+			const U count = countL + countProbe + countDecal;
 
 			auto& c = ctx.m_clusters[i];
 			c.m_firstIdx = 0; // Point to the first empty indices
@@ -647,16 +624,10 @@ void LightBin::binLights(U32 threadId, PtrSize threadsCount, LightBinContext& ct
 					ctx.m_lightIds[offset++] = cluster.m_decalIds[i].getIndex();
 				}
 
-				ctx.m_lightIds[offset++] = countP;
-				for(U i = 0; i < countP; ++i)
-				{
-					ctx.m_lightIds[offset++] = cluster.m_pointIds[i].getIndex();
-				}
-
-				ctx.m_lightIds[offset++] = countS;
-				for(U i = 0; i < countS; ++i)
+				ctx.m_lightIds[offset++] = countL;
+				for(U i = 0; i < countL; ++i)
 				{
-					ctx.m_lightIds[offset++] = cluster.m_spotIds[i].getIndex();
+					ctx.m_lightIds[offset++] = cluster.m_lightIds[i].getIndex();
 				}
 
 				ctx.m_lightIds[offset++] = countProbe;
@@ -680,13 +651,13 @@ void LightBin::binLights(U32 threadId, PtrSize threadsCount, LightBinContext& ct
 I LightBin::writePointLight(const LightComponent& lightc, const MoveComponent& lightMove, LightBinContext& ctx)
 {
 	// Get GPU light
-	I i = ctx.m_pointLightsCount.fetchAdd(1);
+	I i = ctx.m_lightCount.fetchAdd(1);
 
-	ShaderPointLight& slight = ctx.m_pointLights[i];
+	ShaderLight& slight = ctx.m_lights[i];
 
 	Vec4 pos = ctx.m_viewMat * lightMove.getWorldTransform().getOrigin().xyz1();
 
-	slight.m_posRadius = Vec4(pos.xyz(), 1.0 / (lightc.getRadius() * lightc.getRadius()));
+	slight.m_posRadius = Vec4(pos.xyz(), 1.0f / (lightc.getRadius() * lightc.getRadius()));
 	slight.m_diffuseColorShadowmapId = lightc.getDiffuseColor();
 
 	if(!lightc.getShadowEnabled() || !ctx.m_shadowsEnabled)
@@ -700,6 +671,8 @@ I LightBin::writePointLight(const LightComponent& lightc, const MoveComponent& l
 
 	slight.m_specularColorRadius = Vec4(lightc.getSpecularColor().xyz(), lightc.getRadius());
 
+	slight.m_outerCosInnerCos = Vec4(0.0f);
+
 	return i;
 }
 
@@ -708,9 +681,9 @@ I LightBin::writeSpotLight(const LightComponent& lightc,
 	const FrustumComponent* lightFrc,
 	LightBinContext& ctx)
 {
-	I i = ctx.m_spotLightsCount.fetchAdd(1);
+	I i = ctx.m_lightCount.fetchAdd(1);
 
-	ShaderSpotLight& light = ctx.m_spotLights[i];
+	ShaderLight& light = ctx.m_lights[i];
 	F32 shadowmapIndex = INVALID_TEXTURE_INDEX;
 
 	if(lightc.getShadowEnabled() && ctx.m_shadowsEnabled)
@@ -747,20 +720,23 @@ I LightBin::writeSpotLight(const LightComponent& lightc,
 void LightBin::binLight(const SpatialComponent& sp,
 	const LightComponent& lightc,
 	U pos,
-	U lightType,
 	LightBinContext& ctx,
 	ClustererTestResult& testResult) const
 {
+	Bool isSpot;
 	if(lightc.getLightComponentType() == LightComponentType::SPOT)
 	{
 		const FrustumComponent& frc = lightc.getSceneNode().getComponent<FrustumComponent>();
 		ANKI_ASSERT(frc.getFrustum().getType() == FrustumType::PERSPECTIVE);
 		m_clusterer.binPerspectiveFrustum(
 			static_cast<const PerspectiveFrustum&>(frc.getFrustum()), sp.getAabb(), testResult);
+
+		isSpot = true;
 	}
 	else
 	{
 		m_clusterer.bin(sp.getSpatialCollisionShape(), sp.getAabb(), testResult);
+		isSpot = false;
 	}
 
 	// Bin to the correct tiles
@@ -774,21 +750,11 @@ void LightBin::binLight(const SpatialComponent& sp,
 
 		U i = m_clusterer.getClusterCountX() * (z * m_clusterer.getClusterCountY() + y) + x;
 
-		auto& cluster = ctx.m_tempClusters[i];
+		ClusterData& cluster = ctx.m_tempClusters[i];
 
-		switch(lightType)
-		{
-		case 0:
-			i = cluster.m_pointCount.fetchAdd(1) % MAX_TYPED_LIGHTS_PER_CLUSTER;
-			cluster.m_pointIds[i].setIndex(pos);
-			break;
-		case 1:
-			i = cluster.m_spotCount.fetchAdd(1) % MAX_TYPED_LIGHTS_PER_CLUSTER;
-			cluster.m_spotIds[i].setIndex(pos);
-			break;
-		default:
-			ANKI_ASSERT(0);
-		}
+		i = cluster.m_lightCount.fetchAdd(1) % MAX_TYPED_LIGHTS_PER_CLUSTER;
+		cluster.m_lightIds[i].setIndex(pos);
+		cluster.m_lightIds[i].setSpot(isSpot);
 	}
 }
 

+ 1 - 3
src/anki/renderer/LightBin.h

@@ -43,8 +43,7 @@ public:
 		StackAllocator<U8> frameAlloc,
 		U maxLightIndices,
 		Bool shadowsEnabled,
-		StagingGpuMemoryToken& pointLightsToken,
-		StagingGpuMemoryToken& spotLightsToken,
+		StagingGpuMemoryToken& lightsToken,
 		StagingGpuMemoryToken* probesToken,
 		StagingGpuMemoryToken& decalsToken,
 		StagingGpuMemoryToken& clustersToken,
@@ -77,7 +76,6 @@ private:
 	void binLight(const SpatialComponent& sp,
 		const LightComponent& lightc,
 		U pos,
-		U lightType,
 		LightBinContext& ctx,
 		ClustererTestResult& testResult) const;
 

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

@@ -84,8 +84,7 @@ public:
 	{
 	public:
 		StagingGpuMemoryToken m_commonToken;
-		StagingGpuMemoryToken m_pointLightsToken;
-		StagingGpuMemoryToken m_spotLightsToken;
+		StagingGpuMemoryToken m_lightsToken;
 		StagingGpuMemoryToken m_probesToken;
 		StagingGpuMemoryToken m_decalsToken;
 		StagingGpuMemoryToken m_clustersToken;

+ 2 - 3
src/anki/renderer/Volumetric.cpp

@@ -89,8 +89,7 @@ void VolumetricMain::run(RenderingContext& ctx)
 	cmdb->bindTexture(0, 4, m_r->getSm().m_omniTexArray);
 
 	bindUniforms(cmdb, 0, 0, ctx.m_is.m_commonToken);
-	bindUniforms(cmdb, 0, 1, ctx.m_is.m_pointLightsToken);
-	bindUniforms(cmdb, 0, 2, ctx.m_is.m_spotLightsToken);
+	bindUniforms(cmdb, 0, 1, ctx.m_is.m_lightsToken);
 
 	struct Unis
 	{
@@ -99,7 +98,7 @@ void VolumetricMain::run(RenderingContext& ctx)
 		Mat4 m_prevViewProjMatMulInvViewProjMat;
 	};
 
-	Unis* uniforms = allocateAndBindUniforms<Unis*>(sizeof(Unis), cmdb, 0, 3);
+	Unis* uniforms = allocateAndBindUniforms<Unis*>(sizeof(Unis), cmdb, 0, 2);
 	computeLinearizeDepthOptimal(ctx.m_near,
 		ctx.m_far,
 		uniforms->m_linearizeNoiseTexOffsetLayer.x(),