Cogs.Core
CullingManager.cpp
1#include "CullingManager.h"
2
3#include "Context.h"
4
5#include "Services/TaskManager.h"
6
7#include "Systems/Core/CameraSystem.h"
8#include "Systems/Core/RenderSystem.h"
9#include "Systems/Core/TransformSystem.h"
10#include "Systems/Core/SubMeshRenderSystem.h"
11#include "Systems/Core/StaticModelSystem.h"
12#include "Systems/Core/InstancedMeshRenderSystem.h"
13
14void Cogs::Core::CullingManager::initializeCulling()
15{
16 source.count = 0;
17 context->renderSystem->initializeCulling(&source);
18 context->subMeshRenderSystem->initializeCulling(&source);
19 context->staticModelSystem->initializeCulling(&source);
20 context->instancedMeshRenderSystem->initializeCulling(&source);
21}
22
23
24void Cogs::Core::CullingManager::dispatchCulling(CameraData * viewportData)
25{
26 if (!viewportData->cullingData) {
27 viewportData->cullingData = std::shared_ptr<CullingData>(context->cameraSystem->cullingData.create(), [this](CullingData * cd)
28 {
29 if (cd->task.isValid()) {
30 context->taskManager->destroy(cd->task);
31 cd->task = NoTask;
32 }
33 context->cameraSystem->cullingData.destroy(cd);
34 });
35 }
36
37 const size_t count = source.count;
38
39 auto cullData = viewportData->cullingData.get();
40 cullData->viewMatrix = viewportData->viewMatrix;
41 cullData->viewProjection = viewportData->rawProjectionMatrix * viewportData->viewMatrix;
42 cullData->context = context;
43 cullData->source = &source;
44 cullData->results.resize(count);
45 cullData->depths.resize(count);
46 if (!cullData->task.isValid()) {
47 cullData->task = context->taskManager->createGroup();
48 }
49
50 if (!count) return;
51
52 const size_t batchSize = 1024;
53 const size_t batches = (count / batchSize) + 1;
54
55 for (size_t i = 0; i < batches; ++i) {
56 const size_t start = i * batchSize;
57 const size_t end = std::min((i + 1) * batchSize, count);
58
59 if (0.f < viewportData->discardThreshold) {
60 context->taskManager->enqueueChild(cullData->task,
61 [cullData,
62 start,
63 end,
64 discardThresholdSqr = viewportData->discardThreshold,
65 keepThreshold = viewportData->keepThreshold]()
66 {
67 CpuInstrumentationScope(SCOPE_SYSTEMS, "MeshRenderSystem::culling");
68
69 const auto * source = cullData->source;
70 for (size_t i = start; i < end; ++i) {
71 glm::vec3 bbMinWorld = source->bbMinWorld[i];
72 glm::vec3 bbMaxWorld = source->bbMaxWorld[i];
73
74 cullData->results[i] = frustumClassifyBoundingBox(cullData->viewProjection,
75 bbMinWorld,
76 bbMaxWorld,
77 discardThresholdSqr,
78 keepThreshold);
79
80 glm::vec4 p = cullData->viewProjection * glm::vec4(0.5f * (bbMinWorld + bbMaxWorld), 1.f);
81 cullData->depths[i] = p.z / p.w;
82 }
83 });
84 } else {
85 context->taskManager->enqueueChild(cullData->task, [cullData, start, end]() {
86 CpuInstrumentationScope(SCOPE_SYSTEMS, "MeshRenderSystem::culling");
87
88 const auto * source = cullData->source;
89 for (size_t i = start; i < end; ++i) {
90 glm::vec3 bbMinWorld = source->bbMinWorld[i];
91 glm::vec3 bbMaxWorld = source->bbMaxWorld[i];
92
93 cullData->results[i] = frustumClassifyBoundingBox(cullData->viewProjection,
94 bbMinWorld, bbMaxWorld);
95
96 glm::vec4 p = cullData->viewProjection * glm::vec4(0.5f * (bbMinWorld + bbMaxWorld), 1.f);
97 cullData->depths[i] = p.z / p.w;
98 }
99 });
100 }
101 }
102}