2#include "Services/Variables.h"
3#include "Services/QualityService.h"
4#include "Systems/Core/CameraSystem.h"
5#include "Systems/Core/TransformSystem.h"
6#include "Systems/Core/ClipShapeSystem.h"
7#include "Renderer/Renderer.h"
8#include "Utilities/Math.h"
10#include "PotreeSystem.h"
12#include "Foundation/Logging/Logger.h"
13#include "Foundation/BitTwiddling/PowerOfTwo.h"
15#include "Rendering/IGraphicsDevice.h"
16#include "Rendering/ICapabilities.h"
28 constexpr int pointsMaxDefault = 3'000'000;
30 constexpr int chunksMaxDefault = 1000;
32 const Cogs::StringView requestsMaxConcurrentName =
"potree.requests.maxConcurrent";
33 constexpr int requestsMaxConcurrentDefault = 20;
34 const Cogs::StringView requestsMaxPerFrameName =
"potree.requests.maxPerFrame";
35 constexpr int requestsMaxPerFrameDefault = 2;
43 float viewHeightPerPixel;
45 uint32_t pointsMaxCount;
46 uint32_t activeCellCount;
47 uint32_t maxActiveCells;
48 uint32_t requestsInFlight;
49 uint32_t requestsIssuedThisFrame;
50 uint32_t maxConcurrentRequests;
51 uint32_t maxPerFrameRequests;
52 uint32_t maxOctreeSize;
55 uint32_t insideTestEarly1 = 0;
56 uint32_t insideTestEarly2 = 0;
57 uint32_t insideTestClip = 0;
58 uint32_t insideTestSeparated = 0;
59 uint32_t insideTestPassed = 0;
61 bool wantAnotherFrameUpdate =
false;
66 return a.priority < b.priority;
77 ActiveList& activeCellsNew;
78 ActiveList activeCellsOld;
80 glm::u8vec4* tex =
nullptr;
88 static constexpr size_t directionsCount = 7 * 3;
89 glm::vec3 directions[directionsCount];
90 float frustumMin[directionsCount];
91 float frustumMax[directionsCount];
95 size_t clipPlaneCount = 0;
96 bool clipTestInvert =
false;
98 uint32_t numActiveCells = 0;
102 float toleranceSquared = 0.f;
103 float rootToleranceSquared = 0.f;
104 float priority = 0.f;
105 float distanceCutoffScale = 1.f;
106 float distanceCutoffMinimum = -1.f;
107 float distanceCutoffSquared = 0.f;
109 Updater(ManageState& state,
114 activeCellsNew(poData->activeCells)
117 activeCellsOld.swap(activeCellsNew);
118 const glm::mat4& M = poData->worldFromOcttreeFrame;
124 const ClipShapeData& clipData = state.context->clipShapeSystem->getData(clipComp);
126 switch (clipData.shape) {
127 case ClipShapeType::None:
129 case ClipShapeType::Cube:
130 case ClipShapeType::InvertedCube:
131 assert(clipData.planeCount == 6);
132 clipPlaneCount = clipData.planeCount;
133 for (
size_t i = 0; i < clipPlaneCount; i++) {
134 clipPlanes[i] = clipData.
planes[i] * M;
136 clipTestInvert = clipData.shape == ClipShapeType::InvertedCube;
139 assert(
false &&
"Unhandled case");
147 for (
size_t i = 0; i < clipPlaneCount; i++) {
153 clipPlanes[i] = glm::vec4(0, 0, 0, 1);
165 const glm::vec3& boundsMin = poData->octtreeFrame.tightBBoxMin;
166 const glm::vec3& boundsMax = poData->octtreeFrame.tightBBoxMax;
167 glm::vec3 boundsCorners[8] = {
168 glm::vec3(boundsMin.x, boundsMin.y, boundsMin.z),
169 glm::vec3(boundsMax.x, boundsMin.y, boundsMin.z),
170 glm::vec3(boundsMin.x, boundsMax.y, boundsMin.z),
171 glm::vec3(boundsMax.x, boundsMax.y, boundsMin.z),
172 glm::vec3(boundsMin.x, boundsMin.y, boundsMax.z),
173 glm::vec3(boundsMax.x, boundsMin.y, boundsMax.z),
174 glm::vec3(boundsMin.x, boundsMax.y, boundsMax.z),
175 glm::vec3(boundsMax.x, boundsMax.y, boundsMax.z),
177 float clipZMin = std::numeric_limits<float>::max();
178 float clipZMax = -std::numeric_limits<float>::max();
179 glm::mat4 PVM_ = state.P * VM;
180 for (
size_t i = 0; i < 8; i++) {
181 glm::vec4 h = PVM_ * glm::vec4(boundsCorners[i], 1.f);
182 float z = h.z / std::abs(h.w);
183 if (!std::isfinite(z)) {
187 z = state.context->variables->get(
"renderer.reverseDepth",
false) ? 1.f : -1.f;
189 clipZMin = std::min(clipZMin, z);
190 clipZMax = std::max(clipZMax, z);
192 clipZMin = std::max(clipZMin, -1.f);
193 clipZMax = std::min(clipZMax, 1.f);
198 float scale = 2.f / (clipZMax - clipZMin);
199 float bias = -(1.f + scale * clipZMin);
200 PVM = glm::mat4(1.f, 0.f, 0.f, 0.f,
202 0.f, 0.f, scale, 0.f,
203 0.f, 0.f, bias, 1.f) * state.P * VM;
206 PVMinv = glm::inverse(PVM);
207 VMScale = std::cbrt(std::abs(glm::determinant(glm::mat3(VM))));
209 poData->frustum = poData->worldFromOcttreeFrame * PVMinv;
211 eye = euclidean(glm::inverse(VM) * glm::vec4(0, 0, 0, 1));
219 glm::vec3 distancesToBoundaryVolume = glm::abs(eye - glm::clamp(eye, poData->root->tbmin, poData->root->tbmax));
220 float maxDistanceToBoundaryVolue = std::max(distancesToBoundaryVolume.x, std::max(distancesToBoundaryVolume.y, distancesToBoundaryVolume.z));
222 distanceCutoffSquared = distanceCutoff * distanceCutoff;
225 distanceCutoffSquared = -1.f;
233 euclidean(PVMinv * glm::vec4(-1, -1, -1, 1)),
234 euclidean(PVMinv * glm::vec4( 1, -1, -1, 1)),
235 euclidean(PVMinv * glm::vec4(-1, 1, -1, 1)),
236 euclidean(PVMinv * glm::vec4( 1, 1, -1, 1)),
237 euclidean(PVMinv * glm::vec4(-1, -1, 1, 1)),
238 euclidean(PVMinv * glm::vec4( 1, -1, 1, 1)),
239 euclidean(PVMinv * glm::vec4(-1, 1, 1, 1)),
240 euclidean(PVMinv * glm::vec4( 1, 1, 1, 1))
254 directions[ 0] = glm::cross(f[0], glm::vec3(1, 0, 0));
255 directions[ 1] = glm::cross(f[0], glm::vec3(0, 1, 0));
256 directions[ 2] = glm::cross(f[0], glm::vec3(0, 0, 1));
258 directions[ 3] = glm::cross(f[1], glm::vec3(1, 0, 0));
259 directions[ 4] = glm::cross(f[1], glm::vec3(0, 1, 0));
260 directions[ 5] = glm::cross(f[1], glm::vec3(0, 0, 1));
262 directions[ 6] = glm::cross(f[2], glm::vec3(1, 0, 0));
263 directions[ 7] = glm::cross(f[2], glm::vec3(0, 1, 0));
264 directions[ 8] = glm::cross(f[2], glm::vec3(0, 0, 1));
266 directions[ 9] = glm::cross(f[3], glm::vec3(1, 0, 0));
267 directions[10] = glm::cross(f[3], glm::vec3(0, 1, 0));
268 directions[11] = glm::cross(f[3], glm::vec3(0, 0, 1));
270 directions[12] = glm::cross(f[4], glm::vec3(1, 0, 0));
271 directions[13] = glm::cross(f[4], glm::vec3(0, 1, 0));
272 directions[14] = glm::cross(f[4], glm::vec3(0, 0, 1));
274 directions[15] = glm::cross(f[5], glm::vec3(1, 0, 0));
275 directions[16] = glm::cross(f[5], glm::vec3(0, 1, 0));
276 directions[17] = glm::cross(f[5], glm::vec3(0, 0, 1));
278 directions[18] = glm::vec3(1, 0, 0);
279 directions[19] = glm::vec3(0, 1, 0);
280 directions[20] = glm::vec3(0, 0, 1);
288 for (
size_t i = 0; i < directionsCount; i++) {
291 float s = 1.f / glm::length(directions[i]);
292 if (std::isfinite(s)) {
296 directions[i] = glm::vec3(0.f);
300 float max_ = -std::numeric_limits<float>::max();
301 float min_ = std::numeric_limits<float>::max();
302 for (
size_t k = 0; k < 8; k++) {
303 float e = dot(directions[i], F[k]);
304 max_ = std::max(max_, e);
305 min_ = std::min(min_, e);
307 frustumMin[i] = min_;
308 frustumMax[i] = max_;
313 float tolerance = state.viewHeightPerPixel * poData->tolerance;
314 toleranceSquared = tolerance * tolerance;
316 float rootTolerance = state.viewHeightPerPixel * poData->rootTolerance;
317 rootToleranceSquared = rootTolerance * rootTolerance;
322 float rootFootprint = calcCellPriority(state, poData->root);
323 if (0 <= rootFootprint) {
325 priority = rootFootprint;
330 [[nodiscard]]
bool cellInsideFrustum(ManageState& state,
const PotreeCell* cell)
332 const glm::vec3 cellMin = cell->tbmin;
333 const glm::vec3 cellMax = cell->tbmax;
334 glm::vec3 cellCorners[8] = {
335 glm::vec3(cellMin.x, cellMin.y, cellMin.z),
336 glm::vec3(cellMin.x, cellMin.y, cellMax.z),
337 glm::vec3(cellMin.x, cellMax.y, cellMin.z),
338 glm::vec3(cellMin.x, cellMax.y, cellMax.z),
339 glm::vec3(cellMax.x, cellMin.y, cellMin.z),
340 glm::vec3(cellMax.x, cellMin.y, cellMax.z),
341 glm::vec3(cellMax.x, cellMax.y, cellMin.z),
342 glm::vec3(cellMax.x, cellMax.y, cellMax.z),
346 uint32_t allInsideMask = 0b111111;
348 uint32_t anyInsideMask = 0u;
349 for (
size_t i = 0; i < 8; i++) {
350 glm::vec4 p = PVM * glm::vec4(cellCorners[i], 1.f);
351 uint32_t cornerMask =
352 (p.x <= p.w ? 1 : 0) |
353 (p.y <= p.w ? 2 : 0) |
354 (p.z <= p.w ? 4 : 0) |
355 (-p.w <= p.x ? 8 : 0) |
356 (-p.w <= p.y ? 16 : 0) |
357 (-p.w <= p.z ? 32 : 0);
358 anyInsideMask = anyInsideMask | cornerMask;
359 allInsideMask = allInsideMask & cornerMask;
362 if (anyInsideMask != 0b111111) {
364 state.insideTestEarly1++;
369 if (clipPlaneCount) {
371 uint32_t anyInsideClippedMask = 0u;
372 uint32_t allInsideClippedMask = 0b111111;
373 for (
size_t i = 0; i < 8; i++) {
374 glm::vec4 q = glm::vec4(cellCorners[i], 1.f);
375 uint32_t cornerClippedMask =
376 (0.f <= dot(q, clipPlanes[0]) ? (1 << 0) : 0) |
377 (0.f <= dot(q, clipPlanes[1]) ? (1 << 1) : 0) |
378 (0.f <= dot(q, clipPlanes[2]) ? (1 << 2) : 0) |
379 (0.f <= dot(q, clipPlanes[3]) ? (1 << 3) : 0) |
380 (0.f <= dot(q, clipPlanes[4]) ? (1 << 4) : 0) |
381 (0.f <= dot(q, clipPlanes[5]) ? (1 << 5) : 0);
382 anyInsideClippedMask = anyInsideClippedMask | cornerClippedMask;
383 allInsideClippedMask = allInsideClippedMask & cornerClippedMask;
386 if (clipTestInvert ==
false) {
388 if (anyInsideClippedMask != 0b111111) {
389 state.insideTestClip++;
395 if (allInsideClippedMask == 0b111111) {
396 state.insideTestClip++;
402 if (allInsideMask == 0b111111) {
404 state.insideTestEarly2++;
410 for (
size_t i = 0; i < directionsCount; i++) {
411 float ma_ = -std::numeric_limits<float>::max();
412 float mi_ = std::numeric_limits<float>::max();
413 for (
size_t k = 0; k < 8; k++) {
414 float e = dot(directions[i], cellCorners[k]);
415 ma_ = std::max(ma_, e);
416 mi_ = std::min(mi_, e);
419 if (ma_ < frustumMin[i] || frustumMax[i] < mi_) {
421 state.insideTestSeparated++;
426 state.insideTestPassed++;
431 [[nodiscard]]
float calcCellPriority(ManageState& state,
PotreeCell* cell)
433 if (cellInsideFrustum(state, cell)) {
435 const glm::vec3 cellMin = cell->tbmin;
436 const glm::vec3 cellMax = cell->tbmax;
438 const glm::vec3 neareastPoint = glm::clamp(eye, cellMin, cellMax);
439 const float eyeDistanceSquared = glm::distance2(eye, neareastPoint);
440 if (0.f <= distanceCutoffSquared && distanceCutoffSquared < eyeDistanceSquared) {
447 glm::vec3 c = euclidean(VM * glm::vec4(cellMin + cellMax, 2.f));
450 float d2 = dot(c, c);
454 glm::vec3 d = cellMax - cellMin;
457 float r2 = VMScale * VMScale * dot(d, d);
459 float squaredWeight = r2 / d2;
460 if (std::isfinite(squaredWeight)) {
462 if (cell->isRootNode()) {
463 if (rootToleranceSquared <= squaredWeight)
return squaredWeight;
466 if (toleranceSquared <= squaredWeight)
return squaredWeight;
475 assert(cell->kind == PotreeCell::Kind::SubtreeLink);
480 if (cell->linkedSubtree ==
nullptr) {
482 if (state.requestsInFlight < state.maxConcurrentRequests) {
484 if (state.requestsIssuedThisFrame < state.maxPerFrameRequests) {
485 assert(cell->state == PotreeCell::State::None);
486 cell->state = PotreeCell::State::Issued;
487 state.poSystem->issueSubtreeFetch(context, poComp, poData, cell);
488 state.requestsInFlight++;
489 state.requestsIssuedThisFrame++;
493 state.wantAnotherFrameUpdate =
true;
503 auto* subtree = cell->linkedSubtree;
504 if (subtree->state != PotreeSubtree::State::Ready) {
510 if (subtree->cells.empty()) {
515 auto* subtreeRoot = subtree->cells.front();
517 assert(subtreeRoot->kind == PotreeCell::Kind::RegularNode &&
"Invalid subtree");
522 if (subtreeRoot->isActive()) {
523 activeCellsOld.remove(subtreeRoot);
525 subtreeRoot->setActive();
526 activeCellsNew.push(subtreeRoot);
533 [[nodiscard]]
bool updateIteration(
Context* context, ManageState& state)
535 assert(!poData->
lodHeap.empty());
538 std::pop_heap(poData->
lodHeap.begin(), poData->
lodHeap.end(), potreeNodeHeapCmp);
542 if (state.maxActiveCells <= state.activeCellCount) {
546 if (state.maxOctreeSize <= numActiveCells) {
553 if (state.pointsMaxCount < state.pointsCount + cell->pointCount) {
559 state.activeCellCount++;
560 state.pointsCount += cell->pointCount;
563 if ((cell->flags & PotreeCell::Flags::Active) == PotreeCell::Flags::Active) {
564 activeCellsOld.remove(cell);
568 activeCellsNew.push(cell);
572 if (cell->kind == PotreeCell::Kind::SubtreeLink) {
573 cell = handleSubtreeLink(context, state, cell);
574 if (cell ==
nullptr) {
575 return !poData->
lodHeap.empty();
578 assert(cell->kind == PotreeCell::Kind::RegularNode);
584 if (cell->state == PotreeCell::State::None) {
588 if (cell->byteCount == 0) {
589 cell->state = PotreeCell::State::Ready;
591 if (child && child->state != PotreeCell::State::Ready) {
592 child->scaleFactor = cell->scaleFactor;
598 else if (state.requestsInFlight < state.maxConcurrentRequests) {
600 if (state.requestsIssuedThisFrame < state.maxPerFrameRequests) {
601 cell->fetchData(context, state.poSystem, poComp, poData);
602 state.requestsInFlight++;
603 state.requestsIssuedThisFrame++;
607 state.wantAnotherFrameUpdate =
true;
611 return !poData->
lodHeap.empty();
615 for (
unsigned i = 0; i < 8; i++) {
616 if (
auto* child = cell->children[i]; child) {
618 float importance = calcCellPriority(state, child);
623 if (0 <= importance) {
625 std::push_heap(poData->
lodHeap.begin(), poData->
lodHeap.end(), potreeNodeHeapCmp);
629 priority = poData->
lodHeap.front().priority;
631 std::pop_heap(poData->
lodHeap.begin(), poData->
lodHeap.end(), potreeNodeHeapCmp);
632 priority = poData->
lodHeap.back().priority;
633 std::push_heap(poData->
lodHeap.begin(), poData->
lodHeap.end(), potreeNodeHeapCmp);
640 return !poData->
lodHeap.empty();
643 void populateTexture(ManageState& state)
645 poData->octtreeTextureData.resize(state.maxOctreeSize,
false);
646 std::memset(
static_cast<void*
>(poData->octtreeTextureData.data()), ~0u, poData->octtreeTextureData.byteSize());
656 poData->tmpCellPointers.resize(state.maxOctreeSize,
false);
657 std::memset(poData->tmpCellPointers.data(), 0u, poData->tmpCellPointers.byteSize());
659 glm::u8vec4* tex = poData->octtreeTextureData.data();
660 PotreeCell** cells = poData->tmpCellPointers.data();
663 if (poData->root->isActive()) {
664 cells[numCells++] = poData->root;
673 for (
size_t currIx = 0; currIx < numCells; currIx++) {
675 size_t firstChild = numCells;
676 cell->texOffset =
static_cast<uint16_t
>(currIx);
678 unsigned childMask = 0;
679 for (
unsigned k = 0; k < 8; k++) {
680 if (
auto* child = cell->children[k]; (child !=
nullptr) && (child->isActive())) {
681 if (child->kind == PotreeCell::Kind::SubtreeLink) {
682 if (child->linkedSubtree ==
nullptr ||
683 child->linkedSubtree->state != PotreeSubtree::State::Ready ||
684 child->linkedSubtree->cells.empty())
688 child = child->linkedSubtree->cells.front();
689 assert(child->kind == PotreeCell::Kind::RegularNode);
696 assert(numCells < state.maxOctreeSize);
697 childMask |= 1u << k;
698 cells[numCells++] = child;
704 tex[currIx].g =
static_cast<uint8_t
>(firstChild & 0xffu);
705 tex[currIx].b =
static_cast<uint8_t
>(firstChild >> 8);
708 tex[currIx].g = 0xffu;
709 tex[currIx].b = 0xffu;
711 tex[currIx].r =
static_cast<uint8_t
>(childMask);
712 tex[currIx].a = cell->scaleFactor;
721 while (!activeCellsOld.empty()) {
722 auto* cell = activeCellsOld.shift();
724 cell->texOffset =
static_cast<uint16_t
>(~0u);
726 cell->releaseData(context, poData);
728 if (cell->kind == PotreeCell::Kind::SubtreeLink && cell->linkedSubtree) {
729 poData->subtrees.remove(cell->linkedSubtree);
730 inactiveSubtrees.push(cell->linkedSubtree);
731 cell->linkedSubtree =
nullptr;
735 while (!inactiveSubtrees.empty()) {
736 auto* subtree = inactiveSubtrees.shift();
737 assert(subtree->containingCell &&
"Don't delete the root tree");
739 subtree->release(context, poData);
740 poData->subtreeStore.destroy(subtree);
747 bool updaterPointerCmp(
const Updater* a,
const Updater* b)
749 assert(!a->poData->lodHeap.empty());
750 assert(!b->poData->lodHeap.empty());
751 return a->priority < b->priority;
758void Cogs::Core::PotreeSystem::updateLodLevels(
Context* context)
766 state.poSystem =
this;
768 state.V = mainCamData.viewMatrix;
771 state.viewHeightPerPixel = std::sin(mainCamComp->
fieldOfView) / std::max(1.f, glm::length(mainCamData.viewportSize));
774 state.viewHeightPerPixel = 1.f / std::max(1.f, glm::length(mainCamData.viewportSize));
792 state.pointsCount = 0;
793 state.pointsMaxCount =
static_cast<unsigned>(std::max(1,
static_cast<int>(
context->
qualityService->potreeSystemChunkCountScale *
context->
variables->get(pointsMaxName, pointsMaxDefault))));
798 state.activeCellCount = 0;
799 state.maxActiveCells =
static_cast<unsigned>(std::max(1,
static_cast<int>(
context->
qualityService->potreeSystemChunkCountScale *
context->
variables->get(chunksMaxName, chunksMaxDefault))));
800 state.requestsInFlight = requestsInFlight;
801 state.requestsIssuedThisFrame = 0;
802 state.maxConcurrentRequests =
static_cast<unsigned>(std::max(0,
context->
variables->get(requestsMaxConcurrentName, requestsMaxConcurrentDefault)));
803 state.maxPerFrameRequests =
static_cast<uint32_t
>(std::max(0,
context->
variables->get(requestsMaxPerFrameName, requestsMaxPerFrameDefault)));
807 std::vector<Updater> updaters;
808 updaters.reserve(
pool.size());
809 for (
auto& poComp :
pool) {
810 PotreeData* poData = getData(&poComp).poData.get();
811 if (!poComp.
isVisible() || poData->state != PotreeState::Running || poData->root ==
nullptr) {
817 assert(!poData->subtrees.empty());
818 updaters.emplace_back(state, &poComp, poData);
822 state.maxActiveCells = std::min(state.maxActiveCells, state.maxOctreeSize *
static_cast<uint32_t
>(updaters.size()));
825 std::vector<Updater*> updaterHeap;
826 updaterHeap.reserve(updaters.size());
827 for (
auto& updater : updaters) {
828 if (!updater.poData->lodHeap.empty()) {
829 updaterHeap.push_back(&updater);
832 std::make_heap(updaterHeap.begin(), updaterHeap.end(), updaterPointerCmp);
837 while (!updaterHeap.empty()) {
838 std::pop_heap(updaterHeap.begin(), updaterHeap.end(), updaterPointerCmp);
839 if (updaterHeap.back()->updateIteration(
context, state)) {
840 std::push_heap(updaterHeap.begin(), updaterHeap.end(), updaterPointerCmp);
843 updaterHeap.pop_back();
846 for (
auto& updater : updaters) {
848 updater.populateTexture(state);
852 if (state.wantAnotherFrameUpdate) {
855 context->
variables->set(
"potree.instrument.wantAnotherFrameUpdate",
int(state.wantAnotherFrameUpdate));
857 context->
variables->set(
"potree.instrument.currentPointCount",
int(state.pointsCount));
858 context->
variables->set(
"potree.instrument.activeCellCount",
int(state.activeCellCount));
860 context->
variables->set(
"potree.instrument.requests.issuedThisFrame",
int(state.requestsIssuedThisFrame));
861 context->
variables->set(
"potree.instrument.requests.inFlight",
int(state.requestsInFlight));
863 uint32_t insideTestTotal = state.insideTestEarly1 + state.insideTestEarly2 + state.insideTestSeparated + state.insideTestPassed;
864 context->
variables->set(
"potree.instrument.insideTest.total",
int(insideTestTotal));
865 context->
variables->set(
"potree.instrument.insideTest.early1",
int(state.insideTestEarly1));
866 context->
variables->set(
"potree.instrument.insideTest.clip",
int(state.insideTestClip));
867 context->
variables->set(
"potree.instrument.insideTest.early2",
int(state.insideTestEarly2));
868 context->
variables->set(
"potree.instrument.insideTest.separated",
int(state.insideTestSeparated));
869 context->
variables->set(
"potree.instrument.insideTest.passed",
int(state.insideTestPassed));
float fieldOfView
Vertical field of view, given in radians.
ProjectionMode projectionMode
The projection mode to use for the camera.
Sets up a clipping shape that can be used by multiple entities.
Context * context
Pointer to the Context instance the system lives in.
ComponentPool< ComponentType > pool
Pool of components managed by the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
class IRenderer * renderer
Renderer.
std::unique_ptr< class QualityService > qualityService
Quality service instance.
std::unique_ptr< class Variables > variables
Variables service instance.
std::unique_ptr< class Engine > engine
Engine instance.
virtual IGraphicsDevice * getDevice()=0
Get the graphics device used by the renderer.
ComponentModel::ComponentHandle clipShapeComponent
Handle to the currently active clip component, if any.
constexpr bool isVisible() const
Check if the entity is visible or not.
virtual ICapabilities * getCapabilities()=0
Get a pointer to the capability management interface used to query the graphics device capability fla...
Log implementation class.
Provides a weakly referenced view over the contents of a string.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
@ Perspective
Perspective projection.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
ComponentType * resolveComponent() const
Contains data describing a Camera instance and its derived data structured such as matrix data and vi...
glm::mat4 rawProjectionMatrix
Projection matrix that has not been adjusted by the renderer, and is thus appropriate for direct scre...
glm::vec4 planes[6]
Clipping planes in world space.
Component for Point Cloud Display.
std::vector< glm::vec4 > clipPlanes
Deprecated, use clip shapes instead.
bool disableLodUpdates
Debug trigger to disable update of lod calculations.
bool disableCustomClipping
Debug switch to disable clipping of points against custom clipping planes.
float distanceCutoffScale
Cut off chunks that are further away than camera elevation above pointcloud z - minimum times this sc...
float distanceCutoffMinimum
Minimum value for distance-based cut-off, cut-off distance will never be less than this value.
std::vector< PotreeNodeHeapItem > lodHeap
heap used while calculating lod levels
static constexpr size_t MaxClipPlanes
Max available in shader.
Runtime control variable.
uint32_t MaxTexture2DSize
Using D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION as default.
virtual const GraphicsDeviceCapabilities & getDeviceCapabilities() const
Gets the device capabilities in a structure.