|
|
@@ -8,207 +8,145 @@
|
|
|
namespace anki {
|
|
|
|
|
|
//==============================================================================
|
|
|
-/// Sort spatial scene nodes on distance
|
|
|
-struct SortSubspatialsFunctor
|
|
|
-{
|
|
|
- Vec3 origin; ///< The pos of the frustum
|
|
|
- SpatialComponent* sp;
|
|
|
-
|
|
|
- Bool operator()(U32 a, U32 b)
|
|
|
- {
|
|
|
- ANKI_ASSERT(a != b
|
|
|
- && a < sp->getSubSpatialsCount()
|
|
|
- && b < sp->getSubSpatialsCount());
|
|
|
-
|
|
|
- const SpatialComponent& spa = sp->getSubSpatial(a);
|
|
|
- const SpatialComponent& spb = sp->getSubSpatial(b);
|
|
|
-
|
|
|
- F32 dist0 =
|
|
|
- origin.getDistanceSquared(spa.getSpatialOrigin());
|
|
|
- F32 dist1 =
|
|
|
- origin.getDistanceSquared(spb.getSpatialOrigin());
|
|
|
-
|
|
|
- return dist0 < dist1;
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-//==============================================================================
|
|
|
-struct VisibilityTestJob: ThreadpoolTask
|
|
|
+struct VisibilityTestTask: ThreadpoolTask
|
|
|
{
|
|
|
U nodesCount = 0;
|
|
|
SceneGraph* scene = nullptr;
|
|
|
SceneNode* frustumableSn = nullptr;
|
|
|
- Tiler* tiler = nullptr;
|
|
|
SceneFrameAllocator<U8> frameAlloc;
|
|
|
|
|
|
- VisibilityTestResults* visible;
|
|
|
+ VisibilityTestResults* cameraVisible; // out
|
|
|
|
|
|
- /// Handle sub spatials
|
|
|
- Bool handleSubspatials(
|
|
|
- const FrustumComponent& fr,
|
|
|
- SpatialComponent& sp,
|
|
|
- U32*& subSpatialIndices,
|
|
|
- U32& subSpatialIndicesCount)
|
|
|
+ /// Test a frustum component
|
|
|
+ void test(SceneNode& testedNode, Bool isLight,
|
|
|
+ ThreadId threadId, U threadsCount)
|
|
|
{
|
|
|
- Bool fatherSpVisible = true;
|
|
|
- subSpatialIndices = nullptr;
|
|
|
- subSpatialIndicesCount = 0;
|
|
|
+ ANKI_ASSERT(isLight == testedNode.tryGetComponent<LightComponent>());
|
|
|
|
|
|
- // Have subspatials?
|
|
|
- if(sp.getSubSpatialsCount())
|
|
|
- {
|
|
|
- subSpatialIndices =
|
|
|
- frameAlloc.newArray<U32>(sp.getSubSpatialsCount());
|
|
|
-
|
|
|
- U i = 0;
|
|
|
- sp.visitChildren([&](SpatialComponent& subsp)
|
|
|
- {
|
|
|
- // Check
|
|
|
- if(fr.insideFrustum(subsp))
|
|
|
- {
|
|
|
- subSpatialIndices[subSpatialIndicesCount++] = i;
|
|
|
- subsp.enableBits(SpatialComponent::SF_VISIBLE_CAMERA);
|
|
|
- }
|
|
|
- ++i;
|
|
|
- });
|
|
|
+ VisibilityTestResults* visible =
|
|
|
+ frameAlloc.newInstance<VisibilityTestResults>(frameAlloc);
|
|
|
|
|
|
- // Sort them
|
|
|
- SortSubspatialsFunctor functor;
|
|
|
- functor.origin = fr.getFrustumOrigin();
|
|
|
- functor.sp = &sp;
|
|
|
- std::sort(subSpatialIndices,
|
|
|
- subSpatialIndices + subSpatialIndicesCount,
|
|
|
- functor);
|
|
|
-
|
|
|
- // The subSpatialIndicesCount == 0 then the camera is looking
|
|
|
- // something in between all sub spatials
|
|
|
- fatherSpVisible = subSpatialIndicesCount != 0;
|
|
|
- }
|
|
|
+ FrustumComponent& testedFr =
|
|
|
+ testedNode->getComponent<FrustumComponent>();
|
|
|
|
|
|
- return fatherSpVisible;
|
|
|
- }
|
|
|
-
|
|
|
- /// Do the tests
|
|
|
- void operator()(ThreadId threadId, U threadsCount)
|
|
|
- {
|
|
|
+ // Chose the test range and a few other things
|
|
|
U64 start, end;
|
|
|
- choseStartEnd(threadId, threadsCount, nodesCount, start, end);
|
|
|
-
|
|
|
- visible = frameAlloc.newInstance<VisibilityTestResults>(frameAlloc);
|
|
|
-
|
|
|
- FrustumComponent* frustumable = frustumableSn->getFrustumComponent();
|
|
|
- ANKI_ASSERT(frustumable);
|
|
|
+ if(!isLight)
|
|
|
+ {
|
|
|
+ choseStartEnd(threadId, threadsCount, nodesCount, start, end);
|
|
|
+ cameraVisible = visible;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Is light
|
|
|
+ start = 0;
|
|
|
+ end = nodesCount;
|
|
|
+ testedFr.setVisibilityTestResults(visible);
|
|
|
+ }
|
|
|
|
|
|
+ // Iterate range of nodes
|
|
|
scene->iterateSceneNodes(start, end, [&](SceneNode& node)
|
|
|
{
|
|
|
- FrustumComponent* fr = node.getFrustumComponent();
|
|
|
+ FrustumComponent* fr = node.tryGetComponent<FrustumComponent>();
|
|
|
|
|
|
// Skip if it is the same
|
|
|
- if(ANKI_UNLIKELY(frustumable == fr))
|
|
|
+ if(ANKI_UNLIKELY(&testedFr == fr))
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- SpatialComponent* sp = node.getSpatialComponent();
|
|
|
- if(!sp)
|
|
|
+ VisibleNode visibleNode;
|
|
|
+ visibleNode.node = &node;
|
|
|
+
|
|
|
+ // Test all spatial components of that node
|
|
|
+ struct SpatialTemp
|
|
|
{
|
|
|
- return;
|
|
|
- }
|
|
|
+ SpatialComponent* sp;
|
|
|
+ U32 idx;
|
|
|
+ };
|
|
|
+ Array<SpatialTemp, ANKI_MAX_MULTIDRAW_PRIMITIVES> sps;
|
|
|
+
|
|
|
+ U32 i = 0;
|
|
|
+ U count = 0;
|
|
|
+ node.iterateComponentsOfType<SpatialComponent>(
|
|
|
+ [&](SpatialComponent& sp)
|
|
|
+ {
|
|
|
+ if(testedFr.insideFrustum(sp))
|
|
|
+ {
|
|
|
+ // Inside
|
|
|
+ sps[count++] = SpatialTemp{&sp, i};
|
|
|
+
|
|
|
+ sp->enableBits(isLight
|
|
|
+ ? SpatialComponent::SF_VISIBLE_LIGHT
|
|
|
+ : SpatialComponent::SF_VISIBLE_CAMERA);
|
|
|
+ }
|
|
|
|
|
|
- if(!frustumable->insideFrustum(*sp))
|
|
|
+ ++i;
|
|
|
+ });
|
|
|
+
|
|
|
+ if(count == 0)
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // Hierarchical spatial => check subspatials
|
|
|
- U32* subSpatialIndices = nullptr;
|
|
|
- U32 subSpatialIndicesCount = 0;
|
|
|
- if(!handleSubspatials(*frustumable, *sp, subSpatialIndices,
|
|
|
- subSpatialIndicesCount))
|
|
|
+ // Sort spatials
|
|
|
+ Vec3 origin = frustumable.getFrustumOrigin();
|
|
|
+ std::sort(sps.begin(), sps.begin() + count,
|
|
|
+ [&](const SpatialTemp& a, const SpatialTemp& b) -> Bool
|
|
|
{
|
|
|
- return;
|
|
|
+ Vec3 spa = a.sp->getSpatialOrigin();
|
|
|
+ Vec3 spb = b.sp->getSpatialOrigin();
|
|
|
+
|
|
|
+ F32 dist0 = origin.getDistanceSquared(spa);
|
|
|
+ F32 dist1 = origin.getDistanceSquared(spb);
|
|
|
+
|
|
|
+ return dist0 < dist1;
|
|
|
+ });
|
|
|
+
|
|
|
+ // Update the visibleNode
|
|
|
+ visibleNode.spatialsCount = count;
|
|
|
+ for(i = 0; i < count; i++)
|
|
|
+ {
|
|
|
+ visibleNode.spatialIndices[i] = sps[i].idx;
|
|
|
}
|
|
|
|
|
|
- // renderable
|
|
|
- RenderComponent* r = node.getRenderComponent();
|
|
|
- if(r)
|
|
|
+ // Do something with the result
|
|
|
+ RenderComponent* r = node.tryGetComponent<RenderComponent>();
|
|
|
+ if(isLight)
|
|
|
{
|
|
|
- visible->renderables.push_back(VisibleNode(
|
|
|
- &node, subSpatialIndices, subSpatialIndicesCount));
|
|
|
+ if(r && r->castsShadow())
|
|
|
+ {
|
|
|
+ visible->renderables.push_back(visibleNode);
|
|
|
+ }
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- Light* l = node.getLight();
|
|
|
- if(l)
|
|
|
+ if(r)
|
|
|
{
|
|
|
- visible->lights.push_back(VisibleNode(&node, nullptr, 0));
|
|
|
-
|
|
|
- if(l->getShadowEnabled() && fr)
|
|
|
- {
|
|
|
- testLight(node);
|
|
|
- }
|
|
|
+ visible->renderables.push_back(visibleNode);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- return;
|
|
|
+ LightComponent* l = node.tryGetComponent<LightComponent>();
|
|
|
+ if(l)
|
|
|
+ {
|
|
|
+ visible->lights.push_back(
|
|
|
+ VisibleNode(&node, nullptr, 0));
|
|
|
+
|
|
|
+ if(l->getShadowEnabled() && fr)
|
|
|
+ {
|
|
|
+ test(node, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- sp->enableBits(SpatialComponent::SF_VISIBLE_CAMERA);
|
|
|
}); // end for
|
|
|
}
|
|
|
|
|
|
- /// Test an individual light
|
|
|
- void testLight(SceneNode& lightSn)
|
|
|
+ /// Do the tests
|
|
|
+ void operator()(ThreadId threadId, U threadsCount)
|
|
|
{
|
|
|
- ANKI_ASSERT(lightSn.getFrustumComponent() != nullptr);
|
|
|
- FrustumComponent& ref = *lightSn.getFrustumComponent();
|
|
|
-
|
|
|
- // Allocate new visibles
|
|
|
- VisibilityTestResults* lvisible =
|
|
|
- frameAlloc.newInstance<VisibilityTestResults>(frameAlloc);
|
|
|
-
|
|
|
- ref.setVisibilityTestResults(lvisible);
|
|
|
-
|
|
|
- scene->iterateSceneNodes([&](SceneNode& node)
|
|
|
- {
|
|
|
- FrustumComponent* fr = node.getFrustumComponent();
|
|
|
- RenderComponent* r = node.getRenderComponent();
|
|
|
-
|
|
|
- // Wont check the same
|
|
|
- if(ANKI_UNLIKELY(&ref == fr))
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- SpatialComponent* sp = node.getSpatialComponent();
|
|
|
- if(!sp)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if(!ref.insideFrustum(*sp))
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // Hierarchical spatial => check subspatials
|
|
|
- U32* subSpatialIndices = nullptr;
|
|
|
- U32 subSpatialIndicesCount = 0;
|
|
|
- if(!handleSubspatials(ref, *sp, subSpatialIndices,
|
|
|
- subSpatialIndicesCount))
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- sp->enableBits(SpatialComponent::SF_VISIBLE_LIGHT);
|
|
|
-
|
|
|
- if(r && r->castsShadow())
|
|
|
- {
|
|
|
- lvisible->renderables.push_back(VisibleNode(
|
|
|
- &node, subSpatialIndices, subSpatialIndicesCount));
|
|
|
- }
|
|
|
- }); // end lambda
|
|
|
+ test(*frustumableSn, threadId, threadsCount);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
@@ -223,13 +161,12 @@ void doVisibilityTests(SceneNode& fsn, SceneGraph& scene,
|
|
|
// Do the tests in parallel
|
|
|
//
|
|
|
Threadpool& threadPool = ThreadpoolSingleton::get();
|
|
|
- VisibilityTestJob jobs[Threadpool::MAX_THREADS];
|
|
|
+ VisibilityTestTask jobs[Threadpool::MAX_THREADS];
|
|
|
for(U i = 0; i < threadPool.getThreadsCount(); i++)
|
|
|
{
|
|
|
jobs[i].nodesCount = scene.getSceneNodesCount();
|
|
|
jobs[i].scene = &scene;
|
|
|
jobs[i].frustumableSn = &fsn;
|
|
|
- jobs[i].tiler = &r.getTiler();
|
|
|
jobs[i].frameAlloc = scene.getFrameAllocator();
|
|
|
|
|
|
threadPool.assignNewTask(i, &jobs[i]);
|