2#include "Utilities/Math.h"
3#include "Systems/Core/TransformSystem.h"
4#include "Systems/Core/CameraSystem.h"
6#include "Image360System.h"
10 using namespace Cogs::Core::Image360;
12 bool isQuadVisible(
const glm::vec3(&planes)[5],
17 const glm::vec3 corners[4] = {
23 for (
const glm::vec3& plane : planes) {
25 for (
size_t i = 0; i < 4; i++) {
26 anyIn = anyIn || (0.f <= glm::dot(plane, corners[i]));
35 bool initializeQuads(
Context* context,
41 const uint32_t currentFrame,
42 std::vector<DynamicLodTree::Quad>& quads)
44 static const struct Face {
49 {.o = {+1 ,0, 0}, .u = {0, 0, -1}, .v = {0, +1, 0}},
50 {.o = {-1, 0, 0}, .u = {0, 0, +1}, .v = {0, +1, 0}},
51 {.o = {0, +1, 0}, .u = {+1, 0, 0}, .v = {0, 0, -1}},
52 {.o = {0, -1, 0}, .u = {+1, 0, 0}, .v = {0, 0, +1}},
53 {.o = {0, 0, +1}, .u = {+1, 0, 0}, .v = {0, +1, 0}},
54 {.o = {0, 0, -1}, .u = {-1, 0, 0}, .v = {0, +1, 0}}
57 bool allBaseLevelsPresent =
true;
60 for (
size_t i = 0; i < 6; i++) {
61 quads[i].o = faces[i].o;
62 quads[i].u = faces[i].u;
63 quads[i].v = faces[i].v;
64 quads[i].slot = cache.isQuadInCache(context, fetcher, im360Comp, config, currentFrame, 0, i);
65 quads[i].cacheLevelIndex = i;
66 quads[i].encodedTreeIndex = i;
68 if (0 <= quads[i].slot) {
69 tree.data[i] = quads[i].slot << 3;
73 allBaseLevelsPresent =
false;
76 return allBaseLevelsPresent;
79 bool quadRefineIteration(
Context* context,
85 const glm::vec3(&planes)[5],
86 const uint32_t currentFrame,
87 const float cosinePerTile,
88 std::vector<DynamicLodTree::Quad>& quads,
89 std::vector<DynamicLodTree::Quad>& quadsNext)
96 if (config.
treeDepth <= quad.level + 1)
continue;
100 glm::vec3 m00 = glm::normalize(quad.o - quad.u - quad.v);
101 glm::vec3 m10 = glm::normalize(quad.o + quad.u - quad.v);
102 glm::vec3 m01 = glm::normalize(quad.o - quad.u + quad.v);
103 glm::vec3 m11 = glm::normalize(quad.o + quad.u + quad.v);
108 float angleMinCosine = glm::min(glm::min(glm::dot(m00, m10),
110 glm::min(glm::dot(m00, m01),
111 glm::dot(m10, m11)));
113 if (cosinePerTile <= angleMinCosine) {
117 size_t leavesBase = tree.data.size();
118 if (config.treeMaxSize < leavesBase + 4) {
123 size_t childQuadCount = 0;
124 EncodedSlotIx leaves[4] = { -1, -1, -1, -1 };
126 for (
size_t k = 0; k < 4; k++) {
129 glm::vec3 u = 0.5f * quad.u;
130 glm::vec3 v = 0.5f * quad.v;
131 glm::vec3 o = quad.o + ((k & 1) == 0 ? -u : u) + ((k & 2) == 0 ? -v : v);
134 EncodedSlotIx encodedCacheSlot = (quad.slot << 3) + 4 + (EncodedSlotIx)k;
135 if (isQuadVisible(planes, o, u, v)) {
138 size_t childLevel = quad.level + 1;
139 size_t childCacheLevelIndex = 4 * quad.cacheLevelIndex + k;
140 SlotIx cacheSlot = cache.isQuadInCache(context, fetcher, im360Comp, config, currentFrame, childLevel, childCacheLevelIndex);
141 if (0 <= cacheSlot) {
147 .cacheLevelIndex = childCacheLevelIndex,
148 .encodedTreeIndex = leavesBase + k,
151 encodedCacheSlot = cacheSlot << 3;
155 leaves[k] = encodedCacheSlot;
159 if (childQuadCount) {
162 for (
size_t k = 0; k < childQuadCount; k++) {
163 quadsNext.emplace_back(childQuads[k]);
167 for (
size_t k = 0; k < 4; k++) {
168 tree.data.push_back(leaves[k]);
172 tree.data[quad.encodedTreeIndex] = -Image360::SlotIx(leavesBase);
175 quads.swap(quadsNext);
177 return !quads.empty();
184void Cogs::Core::Image360::DynamicLodTree::update(
Context* context,
190 const uint32_t currentFrame,
194 if (trComp ==
nullptr)
return;
197 bool allBaseLevelsPresent = initializeQuads(context, *
this, cache, fetcher, im360Comp, config, currentFrame, quads);
199 rendererData.worldFromLocal = context->transformSystem->getLocalToWorld(trComp);
200 rendererData.localFromWorld = glm::inverse(rendererData.worldFromLocal);
202 const CameraData& camData = context->cameraSystem->getMainCameraData();
203 const float clipSpaceNearPlane = context->
variables->get(
"renderer.reverseDepth",
false) ? 1.f : -1.f;
206 const glm::mat3 localFromView = rendererData.localFromWorld * glm::mat3(camData.inverseViewMatrix);
207 const glm::vec3 fwd = localFromView * glm::vec3(0, 0, -1);
209 const glm::mat4 localFromClip = glm::mat4(localFromView) * camData.inverseProjectionMatrix;
210 const glm::vec3 c00 = euclidean(localFromClip * glm::vec4(-1.0, -1.0, clipSpaceNearPlane, 1));
211 const glm::vec3 c10 = euclidean(localFromClip * glm::vec4(+1.0, -1.0, clipSpaceNearPlane, 1));
212 const glm::vec3 c01 = euclidean(localFromClip * glm::vec4(-1.0, +1.0, clipSpaceNearPlane, 1));
213 const glm::vec3 c11 = euclidean(localFromClip * glm::vec4(+1.0, +1.0, clipSpaceNearPlane, 1));
214 glm::vec3 planes[5] = {
215 glm::normalize(glm::cross(c01, c11)),
216 -glm::normalize(glm::cross(c00, c10)),
217 glm::normalize(glm::cross(c00, c01)),
218 -glm::normalize(glm::cross(c10, c11)),
224 float hAngle = glm::acos(glm::dot(glm::normalize(c00), glm::normalize(c10)));
225 float vAngle = glm::acos(glm::dot(glm::normalize(c00), glm::normalize(c01)));
227 if (vAngle <= hAngle) {
228 anglePerPixel = hAngle / camData.viewportSize.x;
231 anglePerPixel = vAngle / camData.viewportSize.y;
239 float anglePerTile = std::min(glm::pi<float>(), anglePerPixel * comp.subsampling * config.
baseSize);
243 float cosinePerTile = std::cos(std::min(glm::pi<float>(), anglePerTile));
247 if (!std::isfinite(cosinePerTile))
return;
249 if (allBaseLevelsPresent) {
250 while (quadRefineIteration(context, *
this, cache, fetcher, im360Comp, config, planes, currentFrame, cosinePerTile, quads,
quadsNext)) {}
ComponentType * getComponent() const
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class Variables > variables
Variables service instance.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
Contains data describing a Camera instance and its derived data structured such as matrix data and vi...
uint32_t baseSize
Base image size of a cached tile. From json.
uint32_t treeDepth
Depth of tile hierarchy. From json.
std::vector< Quad > quadsNext
Scratch buffers kept here to avoid excessive reallocations.