Browse Source

Adding code for the indirect shadow contribution

Panagiotis Christopoulos Charitos 7 years ago
parent
commit
0020e21d61

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

@@ -54,8 +54,9 @@ Config::Config()
 	newOption("r.final.motionBlurSamples", 32);
 	newOption("r.final.motionBlurSamples", 32);
 
 
 	// Scene
 	// Scene
-	newOption("scene.imageReflectionMaxDistance", 30.0);
 	newOption("scene.earlyZDistance", 10.0, "Objects with distance lower than that will be used in early Z");
 	newOption("scene.earlyZDistance", 10.0, "Objects with distance lower than that will be used in early Z");
+	newOption("scene.reflectionProbeEffectiveDistance", 256.0, "How far reflection probes can look");
+	newOption("scene.reflectionProbeShadowEffectiveDistance", 32.0, "How far to render shadows for reflection probes");
 
 
 	// Globals
 	// Globals
 	newOption("width", 1280);
 	newOption("width", 1280);

+ 29 - 2
src/anki/renderer/Indirect.cpp

@@ -194,7 +194,7 @@ Error Indirect::initShadowMapping(const ConfigSet& cfg)
 
 
 	// RT descr
 	// RT descr
 	m_shadowMapping.m_rtDescr =
 	m_shadowMapping.m_rtDescr =
-		m_r->create2DRenderTargetDescription(resolution, resolution, Format::D16_UNORM, "GI SM");
+		m_r->create2DRenderTargetDescription(resolution * 6, resolution, Format::D16_UNORM, "GI SM");
 	m_shadowMapping.m_rtDescr.bake();
 	m_shadowMapping.m_rtDescr.bake();
 
 
 	// FB descr
 	// FB descr
@@ -830,7 +830,34 @@ Bool Indirect::findBestCacheEntry(U64 probeUuid, U32& cacheEntryIdxAllocated, Bo
 
 
 void Indirect::runShadowMapping(CommandBufferPtr& cmdb)
 void Indirect::runShadowMapping(CommandBufferPtr& cmdb)
 {
 {
-	// TODO
+	for(U faceIdx = 0; faceIdx < 6; ++faceIdx)
+	{
+		ANKI_ASSERT(m_ctx.m_probe);
+		ANKI_ASSERT(m_ctx.m_probe->m_renderQueues[faceIdx]);
+		const RenderQueue& faceRenderQueue = *m_ctx.m_probe->m_renderQueues[faceIdx];
+		ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_uuid != 0);
+		ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_shadowCascadeCount == 1);
+
+		ANKI_ASSERT(faceRenderQueue.m_directionalLight.m_shadowRenderQueues[0]);
+		const RenderQueue& cascadeRenderQueue = *faceRenderQueue.m_directionalLight.m_shadowRenderQueues[0];
+
+		if(cascadeRenderQueue.m_renderables.getSize() == 0)
+		{
+			continue;
+		}
+
+		const U rez = m_shadowMapping.m_rtDescr.m_height;
+		cmdb->setViewport(rez * faceIdx, 0, rez, rez);
+		cmdb->setScissor(rez * faceIdx, 0, rez, rez);
+
+		m_r->getSceneDrawer().drawRange(Pass::SM,
+			cascadeRenderQueue.m_viewMatrix,
+			cascadeRenderQueue.m_viewProjectionMatrix,
+			Mat4::getIdentity(), // Don't care about prev matrices here
+			cmdb,
+			cascadeRenderQueue.m_renderables.getBegin(),
+			cascadeRenderQueue.m_renderables.getEnd());
+	}
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 2 - 1
src/anki/scene/CameraNode.cpp

@@ -86,7 +86,8 @@ Error CameraNode::init(Frustum* frustum)
 	newComponent<FrustumFeedbackComponent>();
 	newComponent<FrustumFeedbackComponent>();
 
 
 	// Spatial component
 	// Spatial component
-	newComponent<SpatialComponent>(this, frustum);
+	SpatialComponent* spatialc = newComponent<SpatialComponent>(this, frustum);
+	spatialc->setUpdateOctreeBounds(false);
 
 
 	return Error::NONE;
 	return Error::NONE;
 }
 }

+ 3 - 2
src/anki/scene/LightNode.cpp

@@ -333,11 +333,12 @@ Error DirectionalLightNode::init()
 	newComponent<MoveComponent>();
 	newComponent<MoveComponent>();
 	newComponent<FeedbackComponent>();
 	newComponent<FeedbackComponent>();
 	newComponent<LightComponent>(LightComponentType::DIRECTIONAL, getSceneGraph().getNewUuid());
 	newComponent<LightComponent>(LightComponentType::DIRECTIONAL, getSceneGraph().getNewUuid());
-	newComponent<SpatialComponent>(this, &m_boundingBox);
+	SpatialComponent* spatialc = newComponent<SpatialComponent>(this, &m_boundingBox);
 
 
-	// Make the bounding box large enough so it will always be visible
+	// Make the bounding box large enough so it will always be visible. Because of that don't update the octree bounds
 	m_boundingBox.setMin(getSceneGraph().getSceneMin());
 	m_boundingBox.setMin(getSceneGraph().getSceneMin());
 	m_boundingBox.setMax(getSceneGraph().getSceneMax());
 	m_boundingBox.setMax(getSceneGraph().getSceneMax());
+	spatialc->setUpdateOctreeBounds(false);
 
 
 	return Error::NONE;
 	return Error::NONE;
 }
 }

+ 6 - 3
src/anki/scene/Octree.cpp

@@ -72,7 +72,7 @@ void Octree::init(const Vec3& sceneAabbMin, const Vec3& sceneAabbMax, U32 maxDep
 	m_sceneAabbMax = sceneAabbMax;
 	m_sceneAabbMax = sceneAabbMax;
 }
 }
 
 
-void Octree::place(const Aabb& volume, OctreePlaceable* placeable)
+void Octree::place(const Aabb& volume, OctreePlaceable* placeable, Bool updateActualSceneBounds)
 {
 {
 	ANKI_ASSERT(placeable);
 	ANKI_ASSERT(placeable);
 	ANKI_ASSERT(testCollisionShapes(volume, Aabb(m_sceneAabbMin, m_sceneAabbMax)) && "volume is outside the scene");
 	ANKI_ASSERT(testCollisionShapes(volume, Aabb(m_sceneAabbMin, m_sceneAabbMax)) && "volume is outside the scene");
@@ -95,8 +95,11 @@ void Octree::place(const Aabb& volume, OctreePlaceable* placeable)
 	++m_placeableCount;
 	++m_placeableCount;
 
 
 	// Update the actual scene bounds
 	// Update the actual scene bounds
-	m_actualSceneAabbMin = m_actualSceneAabbMin.min(volume.getMin().xyz());
-	m_actualSceneAabbMax = m_actualSceneAabbMax.max(volume.getMax().xyz());
+	if(updateActualSceneBounds)
+	{
+		m_actualSceneAabbMin = m_actualSceneAabbMin.min(volume.getMin().xyz());
+		m_actualSceneAabbMax = m_actualSceneAabbMax.max(volume.getMax().xyz());
+	}
 }
 }
 
 
 void Octree::remove(OctreePlaceable& placeable)
 void Octree::remove(OctreePlaceable& placeable)

+ 1 - 1
src/anki/scene/Octree.h

@@ -52,7 +52,7 @@ public:
 
 
 	/// Place or re-place an element in the tree.
 	/// Place or re-place an element in the tree.
 	/// @note It's thread-safe against place and remove methods.
 	/// @note It's thread-safe against place and remove methods.
-	void place(const Aabb& volume, OctreePlaceable* placeable);
+	void place(const Aabb& volume, OctreePlaceable* placeable, Bool updateActualSceneBounds);
 
 
 	/// Remove an element from the tree.
 	/// Remove an element from the tree.
 	/// @note It's thread-safe against place and remove methods.
 	/// @note It's thread-safe against place and remove methods.

+ 2 - 1
src/anki/scene/PhysicsDebugNode.cpp

@@ -72,11 +72,12 @@ Error PhysicsDebugNode::init()
 	ANKI_CHECK(rcomp->init());
 	ANKI_CHECK(rcomp->init());
 
 
 	ObbSpatialComponent* scomp = newComponent<ObbSpatialComponent>(this);
 	ObbSpatialComponent* scomp = newComponent<ObbSpatialComponent>(this);
-	Vec3 center = (getSceneGraph().getSceneMax() + getSceneGraph().getSceneMin()) / 2.0f;
+	const Vec3 center = (getSceneGraph().getSceneMax() + getSceneGraph().getSceneMin()) / 2.0f;
 	scomp->m_obb.setCenter(center.xyz0());
 	scomp->m_obb.setCenter(center.xyz0());
 	scomp->m_obb.setExtend((getSceneGraph().getSceneMax() - center).xyz0());
 	scomp->m_obb.setExtend((getSceneGraph().getSceneMax() - center).xyz0());
 	scomp->m_obb.setRotation(Mat3x4::getIdentity());
 	scomp->m_obb.setRotation(Mat3x4::getIdentity());
 	scomp->setSpatialOrigin(Vec4(0.0f));
 	scomp->setSpatialOrigin(Vec4(0.0f));
+	scomp->setUpdateOctreeBounds(false); // Don't mess with the bounds
 
 
 	return Error::NONE;
 	return Error::NONE;
 }
 }

+ 6 - 4
src/anki/scene/ReflectionProbeNode.cpp

@@ -16,7 +16,8 @@ namespace anki
 {
 {
 
 
 const FrustumComponentVisibilityTestFlag FRUSTUM_TEST_FLAGS =
 const FrustumComponentVisibilityTestFlag FRUSTUM_TEST_FLAGS =
-	FrustumComponentVisibilityTestFlag::RENDER_COMPONENTS | FrustumComponentVisibilityTestFlag::LIGHT_COMPONENTS;
+	FrustumComponentVisibilityTestFlag::RENDER_COMPONENTS | FrustumComponentVisibilityTestFlag::LIGHT_COMPONENTS
+	| FrustumComponentVisibilityTestFlag::DIRECTIONAL_LIGHT_SHADOWS_1_CASCADE;
 
 
 /// Feedback component
 /// Feedback component
 class ReflectionProbeNode::MoveFeedbackComponent : public SceneComponent
 class ReflectionProbeNode::MoveFeedbackComponent : public SceneComponent
@@ -53,7 +54,7 @@ Error ReflectionProbeNode::init(const Vec4& aabbMinLSpace, const Vec4& aabbMaxLS
 	F32 effectiveDistance = aabbMaxLSpace.x() - aabbMinLSpace.x();
 	F32 effectiveDistance = aabbMaxLSpace.x() - aabbMinLSpace.x();
 	effectiveDistance = max(effectiveDistance, aabbMaxLSpace.y() - aabbMinLSpace.y());
 	effectiveDistance = max(effectiveDistance, aabbMaxLSpace.y() - aabbMinLSpace.y());
 	effectiveDistance = max(effectiveDistance, aabbMaxLSpace.z() - aabbMinLSpace.z());
 	effectiveDistance = max(effectiveDistance, aabbMaxLSpace.z() - aabbMinLSpace.z());
-	effectiveDistance = max(effectiveDistance, EFFECTIVE_DISTANCE);
+	effectiveDistance = max(effectiveDistance, getSceneGraph().getLimits().m_reflectionProbeEffectiveDistance);
 
 
 	// Move component first
 	// Move component first
 	newComponent<MoveComponent>();
 	newComponent<MoveComponent>();
@@ -89,8 +90,8 @@ Error ReflectionProbeNode::init(const Vec4& aabbMinLSpace, const Vec4& aabbMaxLS
 		m_cubeSides[i].m_frustum.resetTransform(m_cubeSides[i].m_localTrf);
 		m_cubeSides[i].m_frustum.resetTransform(m_cubeSides[i].m_localTrf);
 
 
 		FrustumComponent* frc = newComponent<FrustumComponent>(this, &m_cubeSides[i].m_frustum);
 		FrustumComponent* frc = newComponent<FrustumComponent>(this, &m_cubeSides[i].m_frustum);
-
 		frc->setEnabledVisibilityTests(FrustumComponentVisibilityTestFlag::NONE);
 		frc->setEnabledVisibilityTests(FrustumComponentVisibilityTestFlag::NONE);
+		frc->setEffectiveShadowDistance(getSceneGraph().getLimits().m_reflectionProbeShadowEffectiveDistance);
 	}
 	}
 
 
 	// Spatial component
 	// Spatial component
@@ -98,7 +99,8 @@ Error ReflectionProbeNode::init(const Vec4& aabbMinLSpace, const Vec4& aabbMaxLS
 	m_aabbMaxLSpace = aabbMaxLSpace.xyz();
 	m_aabbMaxLSpace = aabbMaxLSpace.xyz();
 	m_spatialAabb.setMin(aabbMinLSpace);
 	m_spatialAabb.setMin(aabbMinLSpace);
 	m_spatialAabb.setMax(aabbMaxLSpace);
 	m_spatialAabb.setMax(aabbMaxLSpace);
-	newComponent<SpatialComponent>(this, &m_spatialAabb);
+	SpatialComponent* spatialc = newComponent<SpatialComponent>(this, &m_spatialAabb);
+	spatialc->setUpdateOctreeBounds(false);
 
 
 	// Reflection probe comp
 	// Reflection probe comp
 	ReflectionProbeComponent* reflc = newComponent<ReflectionProbeComponent>(getSceneGraph().getNewUuid());
 	ReflectionProbeComponent* reflc = newComponent<ReflectionProbeComponent>(getSceneGraph().getNewUuid());

+ 0 - 2
src/anki/scene/ReflectionProbeNode.h

@@ -20,8 +20,6 @@ namespace anki
 class ReflectionProbeNode : public SceneNode
 class ReflectionProbeNode : public SceneNode
 {
 {
 public:
 public:
-	const F32 EFFECTIVE_DISTANCE = 256.0f;
-
 	ReflectionProbeNode(SceneGraph* scene, CString name)
 	ReflectionProbeNode(SceneGraph* scene, CString name)
 		: SceneNode(scene, name)
 		: SceneNode(scene, name)
 	{
 	{

+ 5 - 3
src/anki/scene/SceneGraph.cpp

@@ -72,12 +72,14 @@ Error SceneGraph::init(AllocAlignedCallback allocCb,
 	m_alloc = SceneAllocator<U8>(allocCb, allocCbData);
 	m_alloc = SceneAllocator<U8>(allocCb, allocCbData);
 	m_frameAlloc = SceneFrameAllocator<U8>(allocCb, allocCbData, 1 * 1024 * 1024);
 	m_frameAlloc = SceneFrameAllocator<U8>(allocCb, allocCbData, 1 * 1024 * 1024);
 
 
-	m_earlyZDist = config.getNumber("scene.earlyZDistance");
+	// Limits
+	m_limits.m_earlyZDistance = config.getNumber("scene.earlyZDistance");
+	m_limits.m_reflectionProbeEffectiveDistance = config.getNumber("scene.reflectionProbeEffectiveDistance");
+	m_limits.m_reflectionProbeShadowEffectiveDistance =
+		config.getNumber("scene.reflectionProbeShadowEffectiveDistance");
 
 
 	ANKI_CHECK(m_events.init(this));
 	ANKI_CHECK(m_events.init(this));
 
 
-	m_maxReflectionProxyDistance = config.getNumber("scene.imageReflectionMaxDistance");
-
 	m_octree = m_alloc.newInstance<Octree>(m_alloc);
 	m_octree = m_alloc.newInstance<Octree>(m_alloc);
 	m_octree->init(m_sceneMin, m_sceneMax, 5); // TODO
 	m_octree->init(m_sceneMin, m_sceneMax, 5); // TODO
 
 

+ 15 - 16
src/anki/scene/SceneGraph.h

@@ -39,6 +39,15 @@ public:
 	Second m_physicsUpdate ANKI_DBG_NULLIFY;
 	Second m_physicsUpdate ANKI_DBG_NULLIFY;
 };
 };
 
 
+/// SceneGraph limits.
+class SceneGraphLimits
+{
+public:
+	F32 m_earlyZDistance = -1.0f; ///< Objects with distance lower than that will be used in early Z.
+	F32 m_reflectionProbeEffectiveDistance = -1.0f; ///< How far reflection probes can look.
+	F32 m_reflectionProbeShadowEffectiveDistance = -1.0f; ///< How far to render shadows for reflection probes.
+};
+
 /// The scene graph that  all the scene entities
 /// The scene graph that  all the scene entities
 class SceneGraph
 class SceneGraph
 {
 {
@@ -161,6 +170,11 @@ public:
 		return m_stats;
 		return m_stats;
 	}
 	}
 
 
+	const SceneGraphLimits& getLimits() const
+	{
+		return m_limits;
+	}
+
 	const Vec3& getSceneMin() const
 	const Vec3& getSceneMin() const
 	{
 	{
 		return m_sceneMin;
 		return m_sceneMin;
@@ -171,7 +185,6 @@ public:
 		return m_sceneMax;
 		return m_sceneMax;
 	}
 	}
 
 
-anki_internal:
 	ResourceManager& getResourceManager()
 	ResourceManager& getResourceManager()
 	{
 	{
 		return *m_resources;
 		return *m_resources;
@@ -204,22 +217,11 @@ anki_internal:
 		return *m_input;
 		return *m_input;
 	}
 	}
 
 
-	F32 getMaxReflectionProxyDistance() const
-	{
-		ANKI_ASSERT(m_maxReflectionProxyDistance > 0.0);
-		return m_maxReflectionProxyDistance;
-	}
-
 	U64 getNewUuid()
 	U64 getNewUuid()
 	{
 	{
 		return m_nodesUuid.fetchAdd(1);
 		return m_nodesUuid.fetchAdd(1);
 	}
 	}
 
 
-	F32 getEarlyZDistance() const
-	{
-		return m_earlyZDist;
-	}
-
 	Octree& getOctree()
 	Octree& getOctree()
 	{
 	{
 		ANKI_ASSERT(m_octree);
 		ANKI_ASSERT(m_octree);
@@ -260,12 +262,9 @@ private:
 
 
 	Atomic<U32> m_objectsMarkedForDeletionCount = {0};
 	Atomic<U32> m_objectsMarkedForDeletionCount = {0};
 
 
-	F32 m_maxReflectionProxyDistance = 0.0;
-
 	Atomic<U64> m_nodesUuid = {1};
 	Atomic<U64> m_nodesUuid = {1};
 
 
-	F32 m_earlyZDist = -1.0;
-
+	SceneGraphLimits m_limits;
 	SceneGraphStats m_stats;
 	SceneGraphStats m_stats;
 
 
 	/// Put a node in the appropriate containers
 	/// Put a node in the appropriate containers

+ 28 - 12
src/anki/scene/Visibility.cpp

@@ -300,7 +300,7 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 		ANKI_ASSERT(count == 1 && "TODO: Support sub-spatials");
 		ANKI_ASSERT(count == 1 && "TODO: Support sub-spatials");
 
 
 		// Sort sub-spatials
 		// Sort sub-spatials
-		Vec4 origin = testedFrc.getFrustumOrigin();
+		const Vec4 origin = testedFrc.getFrustumOrigin();
 		std::sort(sps.begin(), sps.begin() + count, [origin](const SpatialTemp& a, const SpatialTemp& b) -> Bool {
 		std::sort(sps.begin(), sps.begin() + count, [origin](const SpatialTemp& a, const SpatialTemp& b) -> Bool {
 			const Vec4& spa = a.m_origin;
 			const Vec4& spa = a.m_origin;
 			const Vec4& spb = b.m_origin;
 			const Vec4& spb = b.m_origin;
@@ -341,6 +341,19 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 
 
 		if(lc)
 		if(lc)
 		{
 		{
+			// Check if it casts shadow
+			Bool castsShadow = lc->getShadowEnabled();
+			if(castsShadow)
+			{
+				// Extra check
+
+				// Compute distance from the frustum
+				const Plane& nearPlane = testedFrc.getFrustum().getPlanesWorldSpace()[FrustumPlaneType::NEAR];
+				const F32 distFromFrustum = max(0.0f, sps[0].m_sp->getAabb().testPlane(nearPlane));
+
+				castsShadow = distFromFrustum < testedFrc.getEffectiveShadowDistance();
+			}
+
 			switch(lc->getLightComponentType())
 			switch(lc->getLightComponentType())
 			{
 			{
 			case LightComponentType::POINT:
 			case LightComponentType::POINT:
@@ -348,7 +361,7 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 				PointLightQueueElement* el = result.m_pointLights.newElement(alloc);
 				PointLightQueueElement* el = result.m_pointLights.newElement(alloc);
 				lc->setupPointLightQueueElement(*el);
 				lc->setupPointLightQueueElement(*el);
 
 
-				if(lc->getShadowEnabled()
+				if(castsShadow
 					&& testedFrc.visibilityTestsEnabled(
 					&& testedFrc.visibilityTestsEnabled(
 						   FrustumComponentVisibilityTestFlag::POINT_LIGHT_SHADOWS_ENABLED))
 						   FrustumComponentVisibilityTestFlag::POINT_LIGHT_SHADOWS_ENABLED))
 				{
 				{
@@ -377,7 +390,7 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 				SpotLightQueueElement* el = result.m_spotLights.newElement(alloc);
 				SpotLightQueueElement* el = result.m_spotLights.newElement(alloc);
 				lc->setupSpotLightQueueElement(*el);
 				lc->setupSpotLightQueueElement(*el);
 
 
-				if(lc->getShadowEnabled()
+				if(castsShadow
 					&& testedFrc.visibilityTestsEnabled(FrustumComponentVisibilityTestFlag::SPOT_LIGHT_SHADOWS_ENABLED))
 					&& testedFrc.visibilityTestsEnabled(FrustumComponentVisibilityTestFlag::SPOT_LIGHT_SHADOWS_ENABLED))
 				{
 				{
 					RenderQueue* a = alloc.newInstance<RenderQueue>();
 					RenderQueue* a = alloc.newInstance<RenderQueue>();
@@ -399,27 +412,30 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 				ANKI_ASSERT(lc->getShadowEnabled() == true && "Only with shadow for now");
 				ANKI_ASSERT(lc->getShadowEnabled() == true && "Only with shadow for now");
 
 
 				U cascadeCount;
 				U cascadeCount;
-				if(testedFrc.visibilityTestsEnabled(
-					   FrustumComponentVisibilityTestFlag::DIRECTIONAL_LIGHT_SHADOWS_1_CASCADE))
+				if(ANKI_UNLIKELY(!castsShadow))
 				{
 				{
-					cascadeCount = 1;
+					cascadeCount = 0;
 				}
 				}
 				else if(testedFrc.visibilityTestsEnabled(
 				else if(testedFrc.visibilityTestsEnabled(
-							FrustumComponentVisibilityTestFlag::DIRECTIONAL_LIGHT_SHADOWS_ALL_CASCADES))
+							FrustumComponentVisibilityTestFlag::DIRECTIONAL_LIGHT_SHADOWS_1_CASCADE))
 				{
 				{
-					cascadeCount = MAX_SHADOW_CASCADES;
+					cascadeCount = 1;
 				}
 				}
 				else
 				else
 				{
 				{
-					cascadeCount = 0;
+					ANKI_ASSERT(testedFrc.visibilityTestsEnabled(
+						FrustumComponentVisibilityTestFlag::DIRECTIONAL_LIGHT_SHADOWS_ALL_CASCADES));
+					cascadeCount = MAX_SHADOW_CASCADES;
 				}
 				}
 				ANKI_ASSERT(cascadeCount <= MAX_SHADOW_CASCADES);
 				ANKI_ASSERT(cascadeCount <= MAX_SHADOW_CASCADES);
 
 
 				WeakArray<OrthographicFrustum> cascadeFrustums(
 				WeakArray<OrthographicFrustum> cascadeFrustums(
 					(cascadeCount) ? alloc.newArray<OrthographicFrustum>(cascadeCount) : nullptr, cascadeCount);
 					(cascadeCount) ? alloc.newArray<OrthographicFrustum>(cascadeCount) : nullptr, cascadeCount);
 
 
-				lc->setupDirectionalLightQueueElement(
-					testedFrc.getFrustum(), result.m_directionalLight, cascadeFrustums);
+				lc->setupDirectionalLightQueueElement(testedFrc.getFrustum(),
+					testedFrc.getEffectiveShadowDistance(),
+					result.m_directionalLight,
+					cascadeFrustums);
 
 
 				nextQueues = WeakArray<RenderQueue>(
 				nextQueues = WeakArray<RenderQueue>(
 					(cascadeCount) ? alloc.newArray<RenderQueue>(cascadeCount) : nullptr, cascadeCount);
 					(cascadeCount) ? alloc.newArray<RenderQueue>(cascadeCount) : nullptr, cascadeCount);
@@ -732,7 +748,7 @@ void SceneGraph::doVisibilityTests(SceneNode& fsn, SceneGraph& scene, RenderQueu
 
 
 	VisibilityContext ctx;
 	VisibilityContext ctx;
 	ctx.m_scene = &scene;
 	ctx.m_scene = &scene;
-	ctx.m_earlyZDist = scene.getEarlyZDistance();
+	ctx.m_earlyZDist = scene.getLimits().m_earlyZDistance;
 	ctx.submitNewWork(fsn.getComponent<FrustumComponent>(), rqueue, hive);
 	ctx.submitNewWork(fsn.getComponent<FrustumComponent>(), rqueue, hive);
 
 
 	hive.waitAllTasks();
 	hive.waitAllTasks();

+ 18 - 7
src/anki/scene/components/FrustumComponent.h

@@ -54,12 +54,6 @@ class FrustumComponent : public SceneComponent
 public:
 public:
 	static const SceneComponentType CLASS_TYPE = SceneComponentType::FRUSTUM;
 	static const SceneComponentType CLASS_TYPE = SceneComponentType::FRUSTUM;
 
 
-	struct VisibilityStats
-	{
-		U32 m_renderablesCount = 0;
-		U32 m_lightsCount = 0;
-	};
-
 	/// Pass the frustum here so we can avoid the virtuals
 	/// Pass the frustum here so we can avoid the virtuals
 	FrustumComponent(SceneNode* node, Frustum* frustum);
 	FrustumComponent(SceneNode* node, Frustum* frustum);
 
 
@@ -155,6 +149,8 @@ public:
 				ANKI_ASSERT(0 && "Cannot have them both");
 				ANKI_ASSERT(0 && "Cannot have them both");
 			}
 			}
 		}
 		}
+
+		// TODO
 #endif
 #endif
 	}
 	}
 
 
@@ -191,6 +187,18 @@ public:
 		}
 		}
 	}
 	}
 
 
+	/// How far to render shadows for this frustum.
+	F32 getEffectiveShadowDistance() const
+	{
+		return (m_effectiveShadowDist < 0.0f) ? m_frustum->getFar() : m_effectiveShadowDist;
+	}
+
+	/// Set how far to render shadows for this frustum or set to negative if you want to use the m_frustun's far.
+	void setEffectiveShadowDistance(F32 dist)
+	{
+		m_effectiveShadowDist = dist;
+	}
+
 private:
 private:
 	enum Flags : U16
 	enum Flags : U16
 	{
 	{
@@ -206,7 +214,8 @@ private:
 	Mat4 m_viewProjMat = Mat4::getIdentity(); ///< View projection matrix
 	Mat4 m_viewProjMat = Mat4::getIdentity(); ///< View projection matrix
 	Mat4 m_prevViewProjMat = Mat4::getIdentity();
 	Mat4 m_prevViewProjMat = Mat4::getIdentity();
 
 
-	BitMask<U16> m_flags;
+	/// How far to render shadows for this frustum. If negative it's the m_frustum's far.
+	F32 m_effectiveShadowDist = -1.0f;
 
 
 	class
 	class
 	{
 	{
@@ -215,6 +224,8 @@ private:
 		U32 m_depthMapWidth = 0;
 		U32 m_depthMapWidth = 0;
 		U32 m_depthMapHeight = 0;
 		U32 m_depthMapHeight = 0;
 	} m_coverageBuff; ///< Coverage buffer for extra visibility tests.
 	} m_coverageBuff; ///< Coverage buffer for extra visibility tests.
+
+	BitMask<U16> m_flags;
 };
 };
 /// @}
 /// @}
 
 

+ 5 - 3
src/anki/scene/components/LightComponent.cpp

@@ -95,8 +95,10 @@ Error LightComponent::update(SceneNode& node, Second prevTime, Second crntTime,
 	return Error::NONE;
 	return Error::NONE;
 }
 }
 
 
-void LightComponent::setupDirectionalLightQueueElement(
-	const Frustum& frustum, DirectionalLightQueueElement& el, WeakArray<OrthographicFrustum> cascadeFrustums) const
+void LightComponent::setupDirectionalLightQueueElement(const Frustum& frustum,
+	F32 overrideFrustumFar,
+	DirectionalLightQueueElement& el,
+	WeakArray<OrthographicFrustum> cascadeFrustums) const
 {
 {
 	ANKI_ASSERT(m_type == LightComponentType::DIRECTIONAL);
 	ANKI_ASSERT(m_type == LightComponentType::DIRECTIONAL);
 	ANKI_ASSERT(cascadeFrustums.getSize() <= MAX_SHADOW_CASCADES);
 	ANKI_ASSERT(cascadeFrustums.getSize() <= MAX_SHADOW_CASCADES);
@@ -124,7 +126,7 @@ void LightComponent::setupDirectionalLightQueueElement(
 		const PerspectiveFrustum& pfrustum = static_cast<const PerspectiveFrustum&>(frustum);
 		const PerspectiveFrustum& pfrustum = static_cast<const PerspectiveFrustum&>(frustum);
 		const F32 fovX = pfrustum.getFovX();
 		const F32 fovX = pfrustum.getFovX();
 		const F32 fovY = pfrustum.getFovY();
 		const F32 fovY = pfrustum.getFovY();
-		const F32 far = pfrustum.getFar();
+		const F32 far = (overrideFrustumFar > 0.0f) ? overrideFrustumFar : pfrustum.getFar();
 
 
 		// Gather the edges
 		// Gather the edges
 		Array<Vec4, (MAX_SHADOW_CASCADES + 1) * 4> edgesLocalSpaceStorage;
 		Array<Vec4, (MAX_SHADOW_CASCADES + 1) * 4> edgesLocalSpaceStorage;

+ 5 - 2
src/anki/scene/components/LightComponent.h

@@ -151,10 +151,13 @@ public:
 
 
 	/// Setup a directional queue element.
 	/// Setup a directional queue element.
 	/// @param[in] frustum The frustum that is looking that directional light. Used to calculate the cascades.
 	/// @param[in] frustum The frustum that is looking that directional light. Used to calculate the cascades.
+	/// @param overrideFrustumFar Override frustum's far or set it to <0.0 to ignore that value.
 	/// @param[out] el The queue element to fill out.
 	/// @param[out] el The queue element to fill out.
 	/// @param[out] cascadeFrustums Fill those frustums as well. The size of this array is the count of the cascades.
 	/// @param[out] cascadeFrustums Fill those frustums as well. The size of this array is the count of the cascades.
-	void setupDirectionalLightQueueElement(
-		const Frustum& frustum, DirectionalLightQueueElement& el, WeakArray<OrthographicFrustum> cascadeFrustums) const;
+	void setupDirectionalLightQueueElement(const Frustum& frustum,
+		F32 overrideFrustumFar,
+		DirectionalLightQueueElement& el,
+		WeakArray<OrthographicFrustum> cascadeFrustums) const;
 
 
 private:
 private:
 	U64 m_uuid;
 	U64 m_uuid;

+ 1 - 1
src/anki/scene/components/SpatialComponent.cpp

@@ -39,7 +39,7 @@ Error SpatialComponent::update(SceneNode& node, Second prevTime, Second crntTime
 		m_shape->computeAabb(m_aabb);
 		m_shape->computeAabb(m_aabb);
 		m_markedForUpdate = false;
 		m_markedForUpdate = false;
 
 
-		m_node->getSceneGraph().getOctree().place(m_aabb, &m_octreeInfo);
+		m_node->getSceneGraph().getOctree().place(m_aabb, &m_octreeInfo, m_updateOctreeBounds);
 		m_placed = true;
 		m_placed = true;
 	}
 	}
 
 

+ 10 - 3
src/anki/scene/components/SpatialComponent.h

@@ -81,6 +81,12 @@ public:
 		m_markedForUpdate = true;
 		m_markedForUpdate = true;
 	}
 	}
 
 
+	/// Update the "actual scene bounds" of the octree or not.
+	void setUpdateOctreeBounds(Bool update)
+	{
+		m_updateOctreeBounds = update;
+	}
+
 	/// @name SceneComponent overrides
 	/// @name SceneComponent overrides
 	/// @{
 	/// @{
 	ANKI_USE_RESULT Error update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated) override;
 	ANKI_USE_RESULT Error update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated) override;
@@ -90,12 +96,13 @@ private:
 	SceneNode* m_node;
 	SceneNode* m_node;
 	const CollisionShape* m_shape;
 	const CollisionShape* m_shape;
 	Aabb m_aabb; ///< A faster shape
 	Aabb m_aabb; ///< A faster shape
-	Vec4 m_origin = Vec4(MAX_F32, MAX_F32, MAX_F32, 0.0);
+	Vec4 m_origin = Vec4(MAX_F32, MAX_F32, MAX_F32, 0.0f);
+
+	OctreePlaceable m_octreeInfo;
 
 
 	Bool8 m_markedForUpdate = false;
 	Bool8 m_markedForUpdate = false;
 	Bool8 m_placed = false;
 	Bool8 m_placed = false;
-
-	OctreePlaceable m_octreeInfo;
+	Bool8 m_updateOctreeBounds = true;
 };
 };
 
 
 /// A class that holds spatial information and implements the SpatialComponent virtuals. You just need to update the
 /// A class that holds spatial information and implements the SpatialComponent virtuals. You just need to update the

+ 1 - 1
tests/scene/Octree.cpp

@@ -36,7 +36,7 @@ ANKI_TEST(Scene, Octree)
 			{
 			{
 				// Place
 				// Place
 				placeables[i].m_userData = &placeables[i];
 				placeables[i].m_userData = &placeables[i];
-				octree.place(volume, &placeables[i]);
+				octree.place(volume, &placeables[i], true);
 				placed.push_back(i);
 				placed.push_back(i);
 			}
 			}
 			else if(mode == 1 && placed.size() > 0)
 			else if(mode == 1 && placed.size() > 0)