Browse Source

Omni light shadowmapping

Panagiotis Christopoulos Charitos 10 years ago
parent
commit
6ca22d74d0

+ 3 - 5
include/anki/collision/Frustum.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
-#ifndef ANKI_COLLISION_FRUSTUM_H
-#define ANKI_COLLISION_FRUSTUM_H
+#pragma once
 
 
 #include "anki/collision/CompoundShape.h"
 #include "anki/collision/CompoundShape.h"
 #include "anki/collision/Plane.h"
 #include "anki/collision/Plane.h"
@@ -43,7 +42,7 @@ public:
 	};
 	};
 
 
 	Frustum(Type type)
 	Frustum(Type type)
-	:	m_type(type)
+		: m_type(type)
 	{}
 	{}
 
 
 	virtual ~Frustum()
 	virtual ~Frustum()
@@ -159,7 +158,7 @@ public:
 
 
 	/// Set all
 	/// Set all
 	PerspectiveFrustum(F32 fovX, F32 fovY, F32 near, F32 far)
 	PerspectiveFrustum(F32 fovX, F32 fovY, F32 near, F32 far)
-	:	PerspectiveFrustum()
+		: PerspectiveFrustum()
 	{
 	{
 		setAll(fovX, fovY, near, far);
 		setAll(fovX, fovY, near, far);
 	}
 	}
@@ -358,4 +357,3 @@ private:
 
 
 } // end namespace anki
 } // end namespace anki
 
 
-#endif

+ 2 - 1
include/anki/gr/Enums.h

@@ -152,7 +152,8 @@ enum class TextureType: U8
 	_2D,
 	_2D,
 	_3D,
 	_3D,
 	_2D_ARRAY,
 	_2D_ARRAY,
-	CUBE
+	CUBE,
+	CUBE_ARRAY
 };
 };
 
 
 enum class SamplingFilter: U8
 enum class SamplingFilter: U8

+ 1 - 1
include/anki/gr/Texture.h

@@ -32,7 +32,7 @@ public:
 	TextureType m_type = TextureType::_2D;
 	TextureType m_type = TextureType::_2D;
 	U32 m_width = 0;
 	U32 m_width = 0;
 	U32 m_height = 0;
 	U32 m_height = 0;
-	U32 m_depth = 0; ///< Relevant only for 3D and 2DArray textures
+	U32 m_depth = 0; ///< Relevant only for 3D, 2DArray and CubeArray textures
 	PixelFormat m_format;
 	PixelFormat m_format;
 	U8 m_mipmapsCount = 0;
 	U8 m_mipmapsCount = 0;
 	U8 m_samples = 1;
 	U8 m_samples = 1;

+ 41 - 17
include/anki/renderer/Sm.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
-#ifndef ANKI_RENDERER_SM_H
-#define ANKI_RENDERER_SM_H
+#pragma once
 
 
 #include "anki/renderer/RenderingPass.h"
 #include "anki/renderer/RenderingPass.h"
 #include "anki/Gr.h"
 #include "anki/Gr.h"
@@ -33,13 +32,14 @@ public:
 
 
 	~Sm()
 	~Sm()
 	{
 	{
-		m_sms.destroy(getAllocator());
+		m_spots.destroy(getAllocator());
+		m_omnis.destroy(getAllocator());
 	}
 	}
 
 
 	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
 	ANKI_USE_RESULT Error init(const ConfigSet& initializer);
 	ANKI_USE_RESULT Error run(
 	ANKI_USE_RESULT Error run(
-		SceneNode* shadowCasters[],
-		U32 shadowCastersCount,
+		SArray<SceneNode*> spotShadowCasters,
+		SArray<SceneNode*> omniShadowCasters,
 		CommandBufferPtr& cmdBuff);
 		CommandBufferPtr& cmdBuff);
 
 
 	Bool getEnabled() const
 	Bool getEnabled() const
@@ -55,28 +55,46 @@ public:
 	/// Get max shadow casters
 	/// Get max shadow casters
 	U32 getMaxLightsCount()
 	U32 getMaxLightsCount()
 	{
 	{
-		return m_sms.getSize();
+		return m_spots.getSize();
 	}
 	}
 
 
-	TexturePtr& getTextureArray()
+	TexturePtr& getSpotTextureArray()
 	{
 	{
-		return m_sm2DArrayTex;
+		return m_spotTexArray;
+	}
+
+	TexturePtr& getOmniTextureArray()
+	{
+		return m_omniTexArray;
 	}
 	}
 #endif
 #endif
 
 
 private:
 private:
-	TexturePtr m_sm2DArrayTex;
+	TexturePtr m_spotTexArray;
+	TexturePtr m_omniTexArray;
 
 
-	/// Shadowmap
-	struct Shadowmap
+	class ShadowmapBase
 	{
 	{
+	public:
 		U32 m_layerId;
 		U32 m_layerId;
-		FramebufferPtr m_fb;
 		SceneNode* m_light = nullptr;
 		SceneNode* m_light = nullptr;
 		U32 m_timestamp = 0; ///< Timestamp of last render or light change
 		U32 m_timestamp = 0; ///< Timestamp of last render or light change
 	};
 	};
 
 
-	DArray<Shadowmap> m_sms;
+	class ShadowmapSpot: public ShadowmapBase
+	{
+	public:
+		FramebufferPtr m_fb;
+	};
+
+	class ShadowmapOmni: public ShadowmapBase
+	{
+	public:
+		Array<FramebufferPtr, 6> m_fb;
+	};
+
+	DArray<ShadowmapSpot> m_spots;
+	DArray<ShadowmapOmni> m_omnis;
 
 
 	/// If false then disable SM at all
 	/// If false then disable SM at all
 	Bool8 m_enabled;
 	Bool8 m_enabled;
@@ -94,14 +112,20 @@ private:
 	void finishDraw(CommandBufferPtr& cmdBuff);
 	void finishDraw(CommandBufferPtr& cmdBuff);
 
 
 	/// Find the best shadowmap for that light
 	/// Find the best shadowmap for that light
-	Shadowmap& bestCandidate(SceneNode& light);
+	template<typename TShadowmap, typename TContainer>
+	void bestCandidate(SceneNode& light, TContainer& arr, TShadowmap*& out);
+
+	/// Check if a shadow pass can be skipped.
+	Bool skip(SceneNode& light, ShadowmapBase& sm);
 
 
-	ANKI_USE_RESULT Error doLight(
-		SceneNode& light, CommandBufferPtr& cmdBuff, Shadowmap*& sm);
+	ANKI_USE_RESULT Error doSpotLight(SceneNode& light,
+		CommandBufferPtr& cmdBuff);
+
+	ANKI_USE_RESULT Error doOmniLight(SceneNode& light,
+		CommandBufferPtr& cmdBuff);
 };
 };
 
 
 /// @}
 /// @}
 
 
 } // end namespace anki
 } // end namespace anki
 
 
-#endif

+ 6 - 0
include/anki/scene/FrustumComponent.h

@@ -100,6 +100,12 @@ public:
 		return *m_visible;
 		return *m_visible;
 	}
 	}
 
 
+	const VisibilityTestResults& getVisibilityTestResults() const
+	{
+		ANKI_ASSERT(m_visible != nullptr);
+		return *m_visible;
+	}
+
 	const VisibilityStats& getLastVisibilityStats() const
 	const VisibilityStats& getLastVisibilityStats() const
 	{
 	{
 		return m_stats;
 		return m_stats;

+ 11 - 23
include/anki/scene/Light.h

@@ -3,8 +3,7 @@
 // Code licensed under the BSD License.
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 // http://www.anki3d.org/LICENSE
 
 
-#ifndef ANKI_SCENE_LIGHT_H
-#define ANKI_SCENE_LIGHT_H
+#pragma once
 
 
 #include "anki/scene/SceneNode.h"
 #include "anki/scene/SceneNode.h"
 #include "anki/scene/Forward.h"
 #include "anki/scene/Forward.h"
@@ -34,9 +33,6 @@ public:
 
 
 	ANKI_USE_RESULT Error loadLensFlare(const CString& filename);
 	ANKI_USE_RESULT Error loadLensFlare(const CString& filename);
 
 
-	ANKI_USE_RESULT Error frameUpdate(
-		F32 prevUpdateTime, F32 crntTime) override;
-
 protected:
 protected:
 	/// Called when moved
 	/// Called when moved
 	void onMoveUpdateCommon(MoveComponent& move);
 	void onMoveUpdateCommon(MoveComponent& move);
@@ -44,6 +40,8 @@ protected:
 	/// One of the frustums got updated
 	/// One of the frustums got updated
 	void onShapeUpdateCommon(LightComponent& light);
 	void onShapeUpdateCommon(LightComponent& light);
 
 
+	void frameUpdateCommon();
+
 	virtual void onMoveUpdate(MoveComponent& move) = 0;
 	virtual void onMoveUpdate(MoveComponent& move) = 0;
 
 
 	virtual void onShapeUpdate(LightComponent& light) = 0;
 	virtual void onShapeUpdate(LightComponent& light) = 0;
@@ -54,35 +52,23 @@ class PointLight: public Light
 {
 {
 public:
 public:
 	PointLight(SceneGraph* scene);
 	PointLight(SceneGraph* scene);
+	~PointLight();
 
 
 	ANKI_USE_RESULT Error create(const CString& name);
 	ANKI_USE_RESULT Error create(const CString& name);
 
 
-	/// @name SceneNode virtuals
-	/// @{
 	ANKI_USE_RESULT Error frameUpdate(
 	ANKI_USE_RESULT Error frameUpdate(
 		F32 prevUpdateTime, F32 crntTime) override;
 		F32 prevUpdateTime, F32 crntTime) override;
-	/// @}
 
 
 public:
 public:
-	class ShadowData
+	class ShadowCombo
 	{
 	{
 	public:
 	public:
-#if 0
-		ShadowData(SceneNode* node)
-		:	m_frustumComps{{
-				{node, &m_frustums[0]}, {node, &m_frustums[1]},
-				{node, &m_frustums[2]}, {node, &m_frustums[3]},
-				{node, &m_frustums[4]}, {node, &m_frustums[5]}}}
-		{}
-
-		Array<PerspectiveFrustum, 6> m_frustums;
-		Array<FrustumComponent, 6> m_frustumComps;
-		Array<Transform, 6> m_localTrfs;
-#endif
+		PerspectiveFrustum m_frustum;
+		Transform m_localTrf;
 	};
 	};
 
 
 	Sphere m_sphereW = Sphere(Vec4(0.0), 1.0);
 	Sphere m_sphereW = Sphere(Vec4(0.0), 1.0);
-	ShadowData* m_shadowData = nullptr;
+	DArray<ShadowCombo> m_shadowData;
 
 
 	void onMoveUpdate(MoveComponent& move) override;
 	void onMoveUpdate(MoveComponent& move) override;
 	void onShapeUpdate(LightComponent& light) override;
 	void onShapeUpdate(LightComponent& light) override;
@@ -96,6 +82,9 @@ public:
 
 
 	ANKI_USE_RESULT Error create(const CString& name);
 	ANKI_USE_RESULT Error create(const CString& name);
 
 
+	ANKI_USE_RESULT Error frameUpdate(
+		F32 prevUpdateTime, F32 crntTime) override;
+
 private:
 private:
 	PerspectiveFrustum m_frustum;
 	PerspectiveFrustum m_frustum;
 
 
@@ -106,4 +95,3 @@ private:
 
 
 } // end namespace anki
 } // end namespace anki
 
 
-#endif

+ 1 - 2
include/anki/util/Allocator.h

@@ -286,10 +286,9 @@ public:
 	template<typename Y>
 	template<typename Y>
 	void deleteInstance(Y* ptr)
 	void deleteInstance(Y* ptr)
 	{
 	{
-		typename rebind<Y>::other alloc(*this);
-
 		if(ptr != nullptr)
 		if(ptr != nullptr)
 		{
 		{
+			typename rebind<Y>::other alloc(*this);
 			alloc.destroy(ptr);
 			alloc.destroy(ptr);
 			alloc.deallocate(ptr, 1);
 			alloc.deallocate(ptr, 1);
 		}
 		}

+ 5 - 2
include/anki/util/DArray.h

@@ -316,8 +316,11 @@ public:
 	SArray(T* mem, PtrSize size)
 	SArray(T* mem, PtrSize size)
 		: Base()
 		: Base()
 	{
 	{
-		ANKI_ASSERT(mem);
-		ANKI_ASSERT(size);
+		if(size)
+		{
+			ANKI_ASSERT(mem);
+		}
+
 		Base::m_data = mem;
 		Base::m_data = mem;
 		Base::m_size = size;
 		Base::m_size = size;
 	}
 	}

+ 36 - 4
shaders/IsLp.frag.glsl

@@ -71,7 +71,8 @@ layout(binding = 0) uniform sampler2D u_msRt0;
 layout(binding = 1) uniform sampler2D u_msRt1;
 layout(binding = 1) uniform sampler2D u_msRt1;
 layout(binding = 2) uniform sampler2D u_msRt2;
 layout(binding = 2) uniform sampler2D u_msRt2;
 layout(binding = 3) uniform sampler2D u_msDepthRt;
 layout(binding = 3) uniform sampler2D u_msDepthRt;
-layout(binding = 4) uniform highp sampler2DArrayShadow u_shadowMapArr;
+layout(binding = 4) uniform highp sampler2DArrayShadow u_spotMapArr;
+layout(binding = 5) uniform highp samplerCubeArrayShadow u_omniMapArr;
 
 
 layout(location = 0) in vec2 in_texCoord;
 layout(location = 0) in vec2 in_texCoord;
 layout(location = 1) flat in int in_instanceId;
 layout(location = 1) flat in int in_instanceId;
@@ -200,7 +201,7 @@ float computeShadowFactor(
 		vec2 cordpart1 = texCoords3.xy + poissonDisk[i] / (300.0);
 		vec2 cordpart1 = texCoords3.xy + poissonDisk[i] / (300.0);
 		vec4 tcoord = vec4(cordpart1, cordpart0);
 		vec4 tcoord = vec4(cordpart1, cordpart0);
 
 
-		shadowFactor += texture(u_shadowMapArr, tcoord);
+		shadowFactor += texture(u_spotMapArr, tcoord);
 	}
 	}
 
 
 	return shadowFactor / 4.0;
 	return shadowFactor / 4.0;
@@ -212,6 +213,29 @@ float computeShadowFactor(
 #endif
 #endif
 }
 }
 
 
+//==============================================================================
+float computeShadowFactorOmni(
+	in vec3 frag2Light,
+	in float layer)
+{
+	vec3 dir = -frag2Light;
+	float dist = length(dir);
+	dir /= dist;
+
+	const float f = 1.0 / tan(90.0 * (PI / 180.0) * 0.5);
+	const float near = 0.1;
+	const float far = 5.0;
+	float g = near - far;
+
+	float z = (far + near) / g * dist + (2.0 * far * near) / g;
+	float w = -dist;
+	z /= w;
+
+	float shadowFactor = texture(u_omniMapArr, vec4(-frag2Light, layer), z);
+
+	return shadowFactor;
+}
+
 //==============================================================================
 //==============================================================================
 // Common code for lighting
 // Common code for lighting
 
 
@@ -293,7 +317,15 @@ void main()
 
 
 		LIGHTING_COMMON();
 		LIGHTING_COMMON();
 
 
-		out_color += (specC + diffC) * (att * max(subsurface, lambert));
+		float shadow = 1.0;
+		if(light.diffuseColorShadowmapId.w < 128.0)
+		{
+			shadow = computeShadowFactorOmni(frag2Light,
+				light.diffuseColorShadowmapId.w);
+		}
+
+		out_color += (specC + diffC)
+			* (att * max(subsurface, lambert * shadow));
 	}
 	}
 
 
 	// Spot lights
 	// Spot lights
@@ -331,7 +363,7 @@ void main()
 
 
 		float shadowmapLayerId = light.diffuseColorShadowmapId.w;
 		float shadowmapLayerId = light.diffuseColorShadowmapId.w;
 		float shadow = computeShadowFactor(slight.texProjectionMat,
 		float shadow = computeShadowFactor(slight.texProjectionMat,
-			fragPos, u_shadowMapArr, shadowmapLayerId);
+			fragPos, u_spotMapArr, shadowmapLayerId);
 
 
 		out_color += (diffC + specC)
 		out_color += (diffC + specC)
 			* (att * spot * max(subsurface, lambert * shadow));
 			* (att * spot * max(subsurface, lambert * shadow));

+ 10 - 1
src/gr/gl/FramebufferImpl.cpp

@@ -100,10 +100,19 @@ void FramebufferImpl::attachTextureInternal(
 		break;
 		break;
 	case GL_TEXTURE_2D_ARRAY:
 	case GL_TEXTURE_2D_ARRAY:
 	case GL_TEXTURE_3D:
 	case GL_TEXTURE_3D:
-		ANKI_ASSERT((GLuint)layer < tex.m_depth);
+	case GL_TEXTURE_CUBE_MAP_ARRAY:
+		if(tex.m_target == GL_TEXTURE_CUBE_MAP_ARRAY)
+		{
+			ANKI_ASSERT((GLuint)layer < tex.m_depth * 6);
+		}
+		else
+		{
+			ANKI_ASSERT((GLuint)layer < tex.m_depth);
+		}
 		glFramebufferTextureLayer(
 		glFramebufferTextureLayer(
 			target, attachment, tex.getGlName(), 0, layer);
 			target, attachment, tex.getGlName(), 0, layer);
 		break;
 		break;
+		break;
 	default:
 	default:
 		ANKI_ASSERT(0);
 		ANKI_ASSERT(0);
 		break;
 		break;

+ 12 - 0
src/gr/gl/TextureImpl.cpp

@@ -35,6 +35,9 @@ static GLenum convertTextureType(TextureType type)
 	case TextureType::CUBE:
 	case TextureType::CUBE:
 		out = GL_TEXTURE_CUBE_MAP;
 		out = GL_TEXTURE_CUBE_MAP;
 		break;
 		break;
+	case TextureType::CUBE_ARRAY:
+		out = GL_TEXTURE_CUBE_MAP_ARRAY;
+		break;
 	};
 	};
 
 
 	return out;
 	return out;
@@ -240,6 +243,15 @@ void TextureImpl::create(const TextureInitializer& init)
 			m_width,
 			m_width,
 			m_height);
 			m_height);
 		break;
 		break;
+	case GL_TEXTURE_CUBE_MAP_ARRAY:
+		glTexStorage3D(
+			m_target,
+			m_mipsCount,
+			m_internalFormat,
+			m_width,
+			m_height,
+			init.m_depth * 6);
+		break;
 	case GL_TEXTURE_CUBE_MAP:
 	case GL_TEXTURE_CUBE_MAP:
 	case GL_TEXTURE_2D_ARRAY:
 	case GL_TEXTURE_2D_ARRAY:
 	case GL_TEXTURE_3D:
 	case GL_TEXTURE_3D:

+ 23 - 2
src/renderer/Is.cpp

@@ -293,7 +293,8 @@ Error Is::initInternal(const ConfigSet& config)
 		init.m_textures[1].m_texture = m_r->getMs().getRt1();
 		init.m_textures[1].m_texture = m_r->getMs().getRt1();
 		init.m_textures[2].m_texture = m_r->getMs().getRt2();
 		init.m_textures[2].m_texture = m_r->getMs().getRt2();
 		init.m_textures[3].m_texture = m_r->getMs().getDepthRt();
 		init.m_textures[3].m_texture = m_r->getMs().getDepthRt();
-		init.m_textures[4].m_texture = m_sm.getTextureArray();
+		init.m_textures[4].m_texture = m_sm.getSpotTextureArray();
+		init.m_textures[5].m_texture = m_sm.getOmniTextureArray();
 
 
 		init.m_storageBuffers[0].m_buffer = m_pLightsBuffs[i];
 		init.m_storageBuffers[0].m_buffer = m_pLightsBuffs[i];
 		init.m_storageBuffers[1].m_buffer = m_sLightsBuffs[i];
 		init.m_storageBuffers[1].m_buffer = m_sLightsBuffs[i];
@@ -333,6 +334,8 @@ Error Is::lightPass(CommandBufferPtr& cmdBuff)
 	U visibleSpotLightsCount = 0;
 	U visibleSpotLightsCount = 0;
 	U visibleSpotTexLightsCount = 0;
 	U visibleSpotTexLightsCount = 0;
 	Array<SceneNode*, Sm::MAX_SHADOW_CASTERS> shadowCasters;
 	Array<SceneNode*, Sm::MAX_SHADOW_CASTERS> shadowCasters;
+	Array<SceneNode*, Sm::MAX_SHADOW_CASTERS> omniCasters;
+	U omniCastersCount = 0;
 
 
 	auto it = vi.getLightsBegin();
 	auto it = vi.getLightsBegin();
 	auto lend = vi.getLightsEnd();
 	auto lend = vi.getLightsEnd();
@@ -344,6 +347,11 @@ Error Is::lightPass(CommandBufferPtr& cmdBuff)
 		{
 		{
 		case LightComponent::LightType::POINT:
 		case LightComponent::LightType::POINT:
 			++visiblePointLightsCount;
 			++visiblePointLightsCount;
+
+			if(light.getShadowEnabled())
+			{
+				omniCasters[omniCastersCount++] = node;
+			}
 			break;
 			break;
 		case LightComponent::LightType::SPOT:
 		case LightComponent::LightType::SPOT:
 			{
 			{
@@ -376,7 +384,10 @@ Error Is::lightPass(CommandBufferPtr& cmdBuff)
 	//
 	//
 	// Do shadows pass
 	// Do shadows pass
 	//
 	//
-	ANKI_CHECK(m_sm.run(&shadowCasters[0], visibleSpotTexLightsCount, cmdBuff));
+	ANKI_CHECK(m_sm.run(
+		{&shadowCasters[0], visibleSpotTexLightsCount},
+		{&omniCasters[0], omniCastersCount},
+		cmdBuff));
 
 
 	//
 	//
 	// Write the lights and tiles UBOs
 	// Write the lights and tiles UBOs
@@ -623,6 +634,16 @@ I Is::writePointLight(const LightComponent& lightc,
 
 
 	slight.m_posRadius = Vec4(pos.xyz(), -1.0 / lightc.getRadius());
 	slight.m_posRadius = Vec4(pos.xyz(), -1.0 / lightc.getRadius());
 	slight.m_diffuseColorShadowmapId = lightc.getDiffuseColor();
 	slight.m_diffuseColorShadowmapId = lightc.getDiffuseColor();
+
+	if(!lightc.getShadowEnabled())
+	{
+		slight.m_diffuseColorShadowmapId.w() = 128.0;
+	}
+	else
+	{
+		slight.m_diffuseColorShadowmapId.w() = lightc.getShadowMapIndex();
+	}
+
 	slight.m_specularColorTexId = lightc.getSpecularColor();
 	slight.m_specularColorTexId = lightc.getSpecularColor();
 
 
 	return i;
 	return i;

+ 137 - 62
src/renderer/Sm.cpp

@@ -54,19 +54,22 @@ Error Sm::init(const ConfigSet& config)
 		: SamplingFilter::NEAREST;
 		: SamplingFilter::NEAREST;
 	sminit.m_sampling.m_compareOperation = CompareOperation::LESS_EQUAL;
 	sminit.m_sampling.m_compareOperation = CompareOperation::LESS_EQUAL;
 
 
-	m_sm2DArrayTex = getGrManager().newInstance<Texture>(sminit);
+	m_spotTexArray = getGrManager().newInstance<Texture>(sminit);
 
 
-	// Init sms
-	m_sms.create(getAllocator(), config.getNumber("is.sm.maxLights"));
+	sminit.m_type = TextureType::CUBE_ARRAY;
+	m_omniTexArray = getGrManager().newInstance<Texture>(sminit);;
+
+	// Init 2D layers
+	m_spots.create(getAllocator(), config.getNumber("is.sm.maxLights"));
 
 
 	FramebufferInitializer fbInit;
 	FramebufferInitializer fbInit;
-	fbInit.m_depthStencilAttachment.m_texture = m_sm2DArrayTex;
+	fbInit.m_depthStencilAttachment.m_texture = m_spotTexArray;
 	fbInit.m_depthStencilAttachment.m_loadOperation =
 	fbInit.m_depthStencilAttachment.m_loadOperation =
 		AttachmentLoadOperation::CLEAR;
 		AttachmentLoadOperation::CLEAR;
 	fbInit.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0;
 	fbInit.m_depthStencilAttachment.m_clearValue.m_depthStencil.m_depth = 1.0;
 
 
-	U32 layer = 0;
-	for(Shadowmap& sm : m_sms)
+	U layer = 0;
+	for(ShadowmapSpot& sm : m_spots)
 	{
 	{
 		sm.m_layerId = layer;
 		sm.m_layerId = layer;
 
 
@@ -76,6 +79,25 @@ Error Sm::init(const ConfigSet& config)
 		++layer;
 		++layer;
 	}
 	}
 
 
+	// Init cube layers
+	m_omnis.create(getAllocator(), config.getNumber("is.sm.maxLights"));
+
+	fbInit.m_depthStencilAttachment.m_texture = m_omniTexArray;
+
+	layer = 0;
+	for(ShadowmapOmni& sm : m_omnis)
+	{
+		sm.m_layerId = layer;
+
+		for(U i = 0; i < 6; ++i)
+		{
+			fbInit.m_depthStencilAttachment.m_layer = layer * 6 + i;
+			sm.m_fb[i] = getGrManager().newInstance<Framebuffer>(fbInit);
+		}
+
+		++layer;
+	}
+
 	return ErrorCode::NONE;
 	return ErrorCode::NONE;
 }
 }
 
 
@@ -93,8 +115,8 @@ void Sm::finishDraw(CommandBufferPtr& cmdBuff)
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-Error Sm::run(SceneNode* shadowCasters[], U32 shadowCastersCount,
-	CommandBufferPtr& cmdBuff)
+Error Sm::run(SArray<SceneNode*> spotShadowCasters,
+	SArray<SceneNode*> omniShadowCasters, CommandBufferPtr& cmdBuff)
 {
 {
 	ANKI_ASSERT(m_enabled);
 	ANKI_ASSERT(m_enabled);
 	Error err = ErrorCode::NONE;
 	Error err = ErrorCode::NONE;
@@ -102,13 +124,14 @@ Error Sm::run(SceneNode* shadowCasters[], U32 shadowCastersCount,
 	prepareDraw(cmdBuff);
 	prepareDraw(cmdBuff);
 
 
 	// render all
 	// render all
-	for(U32 i = 0; i < shadowCastersCount; i++)
+	for(SceneNode* node : spotShadowCasters)
 	{
 	{
-		Shadowmap* sm;
-		ANKI_CHECK(doLight(*shadowCasters[i], cmdBuff, sm));
+		ANKI_CHECK(doSpotLight(*node, cmdBuff));
+	}
 
 
-		ANKI_ASSERT(sm != nullptr);
-		(void)sm;
+	for(SceneNode* node : omniShadowCasters)
+	{
+		ANKI_CHECK(doOmniLight(*node, cmdBuff));
 	}
 	}
 
 
 	finishDraw(cmdBuff);
 	finishDraw(cmdBuff);
@@ -117,108 +140,160 @@ Error Sm::run(SceneNode* shadowCasters[], U32 shadowCastersCount,
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-Sm::Shadowmap& Sm::bestCandidate(SceneNode& light)
+template<typename TShadowmap, typename TContainer>
+void Sm::bestCandidate(SceneNode& light, TContainer& arr, TShadowmap*& out)
 {
 {
 	// Allready there
 	// Allready there
-	for(Shadowmap& sm : m_sms)
+	for(TShadowmap& sm : arr)
 	{
 	{
 		if(&light == sm.m_light)
 		if(&light == sm.m_light)
 		{
 		{
-			return sm;
+			out = &sm;
+			return;
 		}
 		}
 	}
 	}
 
 
 	// Find a null
 	// Find a null
-	for(Shadowmap& sm : m_sms)
+	for(TShadowmap& sm : arr)
 	{
 	{
 		if(sm.m_light == nullptr)
 		if(sm.m_light == nullptr)
 		{
 		{
 			sm.m_light = &light;
 			sm.m_light = &light;
 			sm.m_timestamp = 0;
 			sm.m_timestamp = 0;
-			return sm;
+			out = &sm;
+			return;
 		}
 		}
 	}
 	}
 
 
 	// Find an old and replace it
 	// Find an old and replace it
-	Shadowmap* sm = &m_sms[0];
-	for(U i = 1; i < m_sms.getSize(); i++)
+	TShadowmap* sm = &arr[0];
+	for(U i = 1; i < arr.getSize(); i++)
 	{
 	{
-		if(m_sms[i].m_timestamp < sm->m_timestamp)
+		if(arr[i].m_timestamp < sm->m_timestamp)
 		{
 		{
-			sm = &m_sms[i];
+			sm = &arr[i];
 		}
 		}
 	}
 	}
 
 
 	sm->m_light = &light;
 	sm->m_light = &light;
 	sm->m_timestamp = 0;
 	sm->m_timestamp = 0;
-	return *sm;
+	out = sm;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-Error Sm::doLight(
-	SceneNode& light, CommandBufferPtr& cmdBuff, Sm::Shadowmap*& sm)
+Bool Sm::skip(SceneNode& light, ShadowmapBase& sm)
 {
 {
-	sm = &bestCandidate(light);
-
-	FrustumComponent& fr = light.getComponent<FrustumComponent>();
-	VisibilityTestResults& vi = fr.getVisibilityTestResults();
-	LightComponent& lcomp = light.getComponent<LightComponent>();
-
-	//
-	// Find last update
-	//
-	U32 lastUpdate = light.getComponent<MoveComponent>().getTimestamp();
-	lastUpdate = std::max(lastUpdate, fr.getTimestamp());
+	Timestamp lastUpdate = light.getComponent<MoveComponent>().getTimestamp();
 
 
-	auto it = vi.getRenderablesBegin();
-	auto end = vi.getRenderablesEnd();
-	for(; it != end; ++it)
+	Error err = light.iterateComponentsOfType<FrustumComponent>(
+		[&lastUpdate](FrustumComponent& fr)
 	{
 	{
-		SceneNode* node = it->m_node;
+		lastUpdate = max(lastUpdate, fr.getTimestamp());
+		VisibilityTestResults& vi = fr.getVisibilityTestResults();
 
 
-		FrustumComponent* bfr = node->tryGetComponent<FrustumComponent>();
-		if(bfr)
+		auto it = vi.getRenderablesBegin();
+		auto end = vi.getRenderablesEnd();
+		for(; it != end; ++it)
 		{
 		{
-			lastUpdate = std::max(lastUpdate, bfr->getTimestamp());
+			SceneNode* node = it->m_node;
+
+			FrustumComponent* bfr = node->tryGetComponent<FrustumComponent>();
+			if(bfr)
+			{
+				lastUpdate = max(lastUpdate, bfr->getTimestamp());
+			}
+
+			MoveComponent* bmov = node->tryGetComponent<MoveComponent>();
+			if(bmov)
+			{
+				lastUpdate = max(lastUpdate, bmov->getTimestamp());
+			}
+
+			SpatialComponent* sp = node->tryGetComponent<SpatialComponent>();
+			if(sp)
+			{
+				lastUpdate = max(lastUpdate, sp->getTimestamp());
+			}
 		}
 		}
 
 
-		MoveComponent* bmov = node->tryGetComponent<MoveComponent>();
-		if(bmov)
-		{
-			lastUpdate = std::max(lastUpdate, bmov->getTimestamp());
-		}
+		return ErrorCode::NONE;
+	});
+	(void)err;
 
 
-		SpatialComponent* sp = node->tryGetComponent<SpatialComponent>();
-		if(sp)
-		{
-			lastUpdate = std::max(lastUpdate, sp->getTimestamp());
-		}
+	Bool shouldUpdate = lastUpdate >= sm.m_timestamp;
+	if(shouldUpdate)
+	{
+		sm.m_timestamp = getGlobalTimestamp();
+		LightComponent& lcomp = light.getComponent<LightComponent>();
+		lcomp.setShadowMapIndex(sm.m_layerId);
 	}
 	}
 
 
-	Bool shouldUpdate = lastUpdate >= sm->m_timestamp;
-	if(!shouldUpdate)
+	return !shouldUpdate;
+}
+
+//==============================================================================
+Error Sm::doSpotLight(SceneNode& light, CommandBufferPtr& cmdBuff)
+{
+	ShadowmapSpot* sm;
+	bestCandidate(light, m_spots, sm);
+
+	if(skip(light, *sm))
 	{
 	{
 		return ErrorCode::NONE;
 		return ErrorCode::NONE;
 	}
 	}
 
 
-	sm->m_timestamp = getGlobalTimestamp();
-	lcomp.setShadowMapIndex(sm - &m_sms[0]);
+	FrustumComponent& fr = light.getComponent<FrustumComponent>();
+	VisibilityTestResults& vi = fr.getVisibilityTestResults();
 
 
-	//
-	// Render
-	//
 	cmdBuff->bindFramebuffer(sm->m_fb);
 	cmdBuff->bindFramebuffer(sm->m_fb);
 	cmdBuff->setViewport(0, 0, m_resolution, m_resolution);
 	cmdBuff->setViewport(0, 0, m_resolution, m_resolution);
 
 
-	it = vi.getRenderablesBegin();
+	auto it = vi.getRenderablesBegin();
+	auto end = vi.getRenderablesEnd();
 	for(; it != end; ++it)
 	for(; it != end; ++it)
 	{
 	{
 		ANKI_CHECK(m_r->getSceneDrawer().render(light, *it));
 		ANKI_CHECK(m_r->getSceneDrawer().render(light, *it));
 	}
 	}
 
 
-	ANKI_COUNTER_INC(RENDERER_SHADOW_PASSES, (U64)1);
+	ANKI_COUNTER_INC(RENDERER_SHADOW_PASSES, U64(1));
 
 
 	return ErrorCode::NONE;
 	return ErrorCode::NONE;
 }
 }
 
 
+//==============================================================================
+Error Sm::doOmniLight(SceneNode& light, CommandBufferPtr& cmdBuff)
+{
+	ShadowmapOmni* sm;
+	bestCandidate(light, m_omnis, sm);
+
+	if(skip(light, *sm))
+	{
+		return ErrorCode::NONE;
+	}
+
+	cmdBuff->setViewport(0, 0, m_resolution, m_resolution);
+	U frCount = 0;
+
+	Error err = light.iterateComponentsOfType<FrustumComponent>(
+		[&](FrustumComponent& fr) -> Error
+	{
+		cmdBuff->bindFramebuffer(sm->m_fb[frCount]);
+		VisibilityTestResults& vi = fr.getVisibilityTestResults();
+
+		auto it = vi.getRenderablesBegin();
+		auto end = vi.getRenderablesEnd();
+		for(; it != end; ++it)
+		{
+			ANKI_CHECK(m_r->getSceneDrawer().render(light, *it));
+		}
+
+		++frCount;
+		return ErrorCode::NONE;
+	});
+
+	ANKI_COUNTER_INC(RENDERER_SHADOW_PASSES, U64(6));
+
+	return err;
+}
+
 } // end namespace anki
 } // end namespace anki

+ 74 - 33
src/scene/Light.cpp

@@ -89,7 +89,7 @@ Error Light::create(const CString& name,
 }
 }
 
 
 //==============================================================================
 //==============================================================================
-Error Light::frameUpdate(F32 prevUpdateTime, F32 crntTime)
+void Light::frameUpdateCommon()
 {
 {
 	// Update frustum comps shadow info
 	// Update frustum comps shadow info
 	const LightComponent& lc = getComponent<LightComponent>();
 	const LightComponent& lc = getComponent<LightComponent>();
@@ -112,25 +112,11 @@ Error Light::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 		return ErrorCode::NONE;
 		return ErrorCode::NONE;
 	});
 	});
 	(void) err;
 	(void) err;
-
-	return ErrorCode::NONE;
 }
 }
 
 
 //==============================================================================
 //==============================================================================
 void Light::onMoveUpdateCommon(MoveComponent& move)
 void Light::onMoveUpdateCommon(MoveComponent& move)
 {
 {
-	// Update the frustums
-	Error err = iterateComponentsOfType<FrustumComponent>(
-		[&](FrustumComponent& fr) -> Error
-	{
-		fr.markTransformForUpdate();
-		fr.getFrustum().resetTransform(move.getWorldTransform());
-
-		return ErrorCode::NONE;
-	});
-
-	(void)err;
-
 	// Update the spatial
 	// Update the spatial
 	SpatialComponent& sp = getComponent<SpatialComponent>();
 	SpatialComponent& sp = getComponent<SpatialComponent>();
 	sp.markForUpdate();
 	sp.markForUpdate();
@@ -191,6 +177,12 @@ PointLight::PointLight(SceneGraph* scene)
 	: Light(scene)
 	: Light(scene)
 {}
 {}
 
 
+//==============================================================================
+PointLight::~PointLight()
+{
+	m_shadowData.destroy(getSceneAllocator());
+}
+
 //==============================================================================
 //==============================================================================
 Error PointLight::create(const CString& name)
 Error PointLight::create(const CString& name)
 {
 {
@@ -201,48 +193,78 @@ Error PointLight::create(const CString& name)
 void PointLight::onMoveUpdate(MoveComponent& move)
 void PointLight::onMoveUpdate(MoveComponent& move)
 {
 {
 	onMoveUpdateCommon(move);
 	onMoveUpdateCommon(move);
+
+	// Update the frustums
+	U count = 0;
+	Error err = iterateComponentsOfType<FrustumComponent>(
+		[&](FrustumComponent& fr) -> Error
+	{
+		fr.markTransformForUpdate();
+		fr.getFrustum().resetTransform(
+			move.getWorldTransform().combineTransformations(
+			m_shadowData[count++].m_localTrf));
+
+		return ErrorCode::NONE;
+	});
+
+	(void)err;
+
 	m_sphereW.setCenter(move.getWorldTransform().getOrigin());
 	m_sphereW.setCenter(move.getWorldTransform().getOrigin());
 }
 }
 
 
 //==============================================================================
 //==============================================================================
 void PointLight::onShapeUpdate(LightComponent& light)
 void PointLight::onShapeUpdate(LightComponent& light)
 {
 {
-	onShapeUpdateCommon(light);
+	for(ShadowCombo& c : m_shadowData)
+	{
+		c.m_frustum.setFar(light.getRadius());
+	}
+
 	m_sphereW.setRadius(light.getRadius());
 	m_sphereW.setRadius(light.getRadius());
+
+	onShapeUpdateCommon(light);
 }
 }
 
 
 //==============================================================================
 //==============================================================================
 Error PointLight::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 Error PointLight::frameUpdate(F32 prevUpdateTime, F32 crntTime)
 {
 {
-#if 0
-	if(getShadowEnabled() && m_shadowData == nullptr)
+	if(getComponent<LightComponent>().getShadowEnabled()
+		&& !m_shadowData.isEmpty())
 	{
 	{
-		m_shadowData = getSceneAllocator().newInstance<ShadowData>(this);
-		if(m_shadowData == nullptr)
-		{
-			return ErrorCode::OUT_OF_MEMORY;
-		}
+		m_shadowData.create(getSceneAllocator(), 6);
 
 
 		const F32 ang = toRad(90.0);
 		const F32 ang = toRad(90.0);
-		F32 dist = m_sphereW.getRadius();
+		const F32 dist = m_sphereW.getRadius();
+		const F32 zNear = 0.1;
 
 
 		for(U i = 0; i < 6; i++)
 		for(U i = 0; i < 6; i++)
 		{
 		{
-			m_shadowData->m_frustums[i].setAll(ang, ang, 0.1, dist);
-			m_shadowData->m_localTrfs[i] = Transform::getIdentity();
+			m_shadowData[i].m_frustum.setAll(ang, ang, zNear, dist);
+			m_shadowData[i].m_localTrf = Transform::getIdentity();
+
+			FrustumComponent* comp =
+				getSceneAllocator().newInstance<FrustumComponent>(this,
+				&m_shadowData[i].m_frustum);
+
+			addComponent(comp, true);
 		}
 		}
 
 
-		auto& trfs = m_shadowData->m_localTrfs;
 		Vec3 axis = Vec3(0.0, 1.0, 0.0);
 		Vec3 axis = Vec3(0.0, 1.0, 0.0);
-		trfs[1].setRotation(Mat3x4(Mat3(Axisang(ang, axis))));
-		trfs[2].setRotation(Mat3x4(Mat3(Axisang(ang * 2.0, axis))));
-		trfs[3].setRotation(Mat3x4(Mat3(Axisang(ang * 3.0, axis))));
+		m_shadowData[1].m_localTrf.setRotation(
+			Mat3x4(Mat3(Axisang(ang, axis))));
+		m_shadowData[2].m_localTrf.setRotation(
+			Mat3x4(Mat3(Axisang(ang * 2.0, axis))));
+		m_shadowData[3].m_localTrf.setRotation(
+			Mat3x4(Mat3(Axisang(ang * 3.0, axis))));
 
 
 		axis = Vec3(1.0, 0.0, 0.0);
 		axis = Vec3(1.0, 0.0, 0.0);
-		trfs[4].setRotation(Mat3x4(Mat3(Axisang(ang, axis))));
-		trfs[5].setRotation(Mat3x4(Mat3(Axisang(-ang, axis))));
+		m_shadowData[4].m_localTrf.setRotation(
+			Mat3x4(Mat3(Axisang(ang, axis))));
+		m_shadowData[5].m_localTrf.setRotation(
+			Mat3x4(Mat3(Axisang(-ang, axis))));
 	}
 	}
-#endif
+
+	frameUpdateCommon();
 
 
 	return ErrorCode::NONE;
 	return ErrorCode::NONE;
 }
 }
@@ -275,6 +297,18 @@ Error SpotLight::create(const CString& name)
 //==============================================================================
 //==============================================================================
 void SpotLight::onMoveUpdate(MoveComponent& move)
 void SpotLight::onMoveUpdate(MoveComponent& move)
 {
 {
+	// Update the frustums
+	Error err = iterateComponentsOfType<FrustumComponent>(
+		[&](FrustumComponent& fr) -> Error
+	{
+		fr.markTransformForUpdate();
+		fr.getFrustum().resetTransform(move.getWorldTransform());
+
+		return ErrorCode::NONE;
+	});
+
+	(void)err;
+
 	onMoveUpdateCommon(move);
 	onMoveUpdateCommon(move);
 }
 }
 
 
@@ -287,4 +321,11 @@ void SpotLight::onShapeUpdate(LightComponent& light)
 		0.5, light.getDistance());
 		0.5, light.getDistance());
 }
 }
 
 
+//==============================================================================
+Error SpotLight::frameUpdate(F32 prevUpdateTime, F32 crntTime)
+{
+	frameUpdateCommon();
+	return ErrorCode::NONE;
+}
+
 } // end namespace anki
 } // end namespace anki

+ 11 - 13
testapp/Main.cpp

@@ -43,7 +43,7 @@ App* app;
 ModelNode* horse;
 ModelNode* horse;
 PerspectiveCamera* cam;
 PerspectiveCamera* cam;
 
 
-#define NO_PLAYER 0
+#define NO_PLAYER 1
 
 
 Bool profile = false;
 Bool profile = false;
 
 
@@ -118,21 +118,19 @@ Error init()
 	}
 	}
 #endif
 #endif
 
 
-#if 0
-	err = scene.newSceneNode<SpotLight>("spot0", spot);
-	if(err) return err;
+#if 1
+	PointLight* plight;
+	scene.newSceneNode<PointLight>("spot0", plight);
 
 
-	lightc = spot->tryGetComponent<LightComponent>();
-	lightc->setOuterAngle(toRad(35.0));
-	lightc->setInnerAngle(toRad(15.0));
-	lightc->setDiffuseColor(Vec4(1.0));
+	lightc = plight->tryGetComponent<LightComponent>();
+	lightc->setDiffuseColor(Vec4(0.0, 10.0, 0.0, 1.0));
 	lightc->setSpecularColor(Vec4(1.2));
 	lightc->setSpecularColor(Vec4(1.2));
-	lightc->setDistance(30.0);
+	lightc->setDistance(5.0);
 	lightc->setShadowEnabled(true);
 	lightc->setShadowEnabled(true);
 
 
-	move = spot->tryGetComponent<MoveComponent>();
-	move->setLocalTransform(Transform(Vec4(8.27936, 5.86285, 1.85526, 0.0),
-		Mat3x4(Quat(-0.125117, 0.620465, 0.154831, 0.758544)), 1.0));
+	move = plight->tryGetComponent<MoveComponent>();
+	move->setLocalTransform(Transform(Vec4(-0.0, 4.0, -3.0, 0.0),
+		Mat3x4::getIdentity(), 1.0));
 
 
 #endif
 #endif
 
 
@@ -352,7 +350,7 @@ Error mainLoopExtra(App& app, void*, Bool& quit)
 	}
 	}
 	if(in.getKey(KeyCode::_2))
 	if(in.getKey(KeyCode::_2))
 	{
 	{
-		mover = &scene.findSceneNode("horse").getComponent<MoveComponent>();
+		mover = &scene.findSceneNode("Point_058").getComponent<MoveComponent>();
 	}
 	}
 	if(in.getKey(KeyCode::_3))
 	if(in.getKey(KeyCode::_3))
 	{
 	{