1#include "AdaptivePlanarGridSystem.h"
3#include "Foundation/Logging/Logger.h"
5#include "Components/Appearance/MaterialComponent.h"
6#include "Components/Core/SubMeshRenderComponent.h"
7#include "Components/Core/MeshComponent.h"
8#include "Components/Core/TransformComponent.h"
9#include "Components/Core/LodComponent.h"
10#include "Components/Core/SceneComponent.h"
12#include "Systems/Core/CameraSystem.h"
13#include "Systems/Core/TransformSystem.h"
14#include "Systems/Core/SubMeshRenderSystem.h"
16#include "Resources/Mesh.h"
17#include "Resources/MeshManager.h"
18#include "Resources/VertexFormats.h"
19#include "Resources/MaterialManager.h"
21#include "Utilities/FrustumClassification.h"
22#include "Utilities/Simplex.h"
25#include "EntityStore.h"
32using std::numeric_limits;
131 size_t maxTiles = 1000;
133 std::vector<uint8_t> simplexScratch;
134 std::vector<AdaptivePlanarGridQuadTreeNode> quadTree;
135 std::vector<AdaptivePlanarGridIndex> leaves;
136 std::list<AdaptivePlanarGridRefinableNode> refineQueue;
151 vec3 euclidean(
const vec4& h)
153 return (1.f / h.w)*vec3(h);
158 glm::mat4 worldToView;
159 glm::mat4 worldToClip;
160 glm::mat4 viewToWorld;
161 glm::vec3 worldUnitXY;
162 glm::vec2 viewportSize;
163 float nearDistance = 0.0f;
164 float farDistance = 0.0f;
168 void analyzeView(
Context* context,
171 const std::vector<CameraState>& cameras,
172 bool updateDebugGraphics)
177 gridData.currentExtentMin = dvec2(0.0);
178 gridData.currentExtentMax = dvec2(0.0);
184 auto bboxSize = bboxMax - bboxMin;
186 dvec2 smallestExtentMin(std::numeric_limits<double>::max());
187 dvec2 smallestExtentMax(-std::numeric_limits<double>::max());
189 for (
auto & camera : cameras) {
192 auto rows = glm::dmat4(glm::transpose(camera.worldToClip));
193 auto l = rows[3] + rows[0];
194 auto r = rows[3] - rows[0];
195 auto b = rows[3] + rows[1];
196 auto t = rows[3] - rows[1];
198 double restrictions[7 * 4] =
200 1.0, 0.0, 0.0, bboxSize.x,
201 0.0, 1.0, 0.0, bboxSize.y,
202 0.0, 0.0, 1.0, bboxSize.z,
203 -l.x, -l.y, -l.z, l.w + glm::dot(glm::dvec3(l),bboxMin),
204 -r.x, -r.y, -r.z, r.w + glm::dot(glm::dvec3(r),bboxMin),
205 -b.x, -b.y, -b.z, b.w + glm::dot(glm::dvec3(b),bboxMin),
206 -t.x, -t.y, -t.z, t.w + glm::dot(glm::dvec3(t),bboxMin)
209 double objectives[4 * 3] = {
216 double solutions[4 * 3];
218 (uintptr_t)simplexScratch.data(),
224 if (rv == SimplexResult::NoFeasibleSolutions) {
226 else if (rv != SimplexResult::OptimalSolutionFound) {
227 smallestExtentMin = dvec2(bboxMin);
228 smallestExtentMax = dvec2(bboxMax);
233 glm::dvec2 minWorld = dvec2(solutions[0 * 3 + 0], solutions[0 * 3 + 1]);
234 glm::dvec2 maxWorld = minWorld;
235 for (
int i = 1; i < 4; i++) {
236 auto p = dvec2(solutions[i * 3 + 0], solutions[i * 3 + 1]);
237 minWorld = glm::min(minWorld, p);
238 maxWorld = glm::max(maxWorld, p);
242 smallestExtentMin = glm::min(smallestExtentMin, glm::max(minWorld + glm::dvec2(bboxMin), glm::dvec2(bboxMin)));
243 smallestExtentMax = glm::max(smallestExtentMax, glm::min(maxWorld + glm::dvec2(bboxMin), glm::dvec2(bboxMax)));
248 if ((smallestExtentMax.x - smallestExtentMin.x < std::numeric_limits<float>::epsilon())
249 || (smallestExtentMax.y - smallestExtentMin.y < std::numeric_limits<float>::epsilon()))
251 gridData.currentExtentMin = dvec2(0.0);
252 gridData.currentExtentMax = dvec2(0.0);
256 if ((gridData.currentExtentMin.x <= smallestExtentMin.x)
257 && (gridData.currentExtentMin.y <= smallestExtentMin.y)
258 && (smallestExtentMax.x <= gridData.currentExtentMax.x)
259 && (smallestExtentMax.y <= gridData.currentExtentMax.y))
262 dvec2 A = gridData.currentExtentMax - gridData.currentExtentMin;
263 dvec2 B = smallestExtentMax - smallestExtentMin;
264 if (B.x > 0.5*A.x && B.y > 0.5*A.y) {
272 dvec2 delta = smallestExtentMax - smallestExtentMin;
273 gridData.currentExtentMin = glm::max(smallestExtentMin - 0.25 * delta, glm::dvec2(bboxMin));
274 gridData.currentExtentMax = glm::min(smallestExtentMax + 0.25 * delta, glm::dvec2(bboxMax));
277 if (updateDebugGraphics) {
278 std::vector<glm::vec3> p;
279 p.push_back(glm::vec3(smallestExtentMin.x, smallestExtentMin.y, 0.f));
280 p.push_back(glm::vec3(smallestExtentMax.x, smallestExtentMin.y, 0.f));
282 p.push_back(glm::vec3(smallestExtentMax.x, smallestExtentMin.y, 0.f));
283 p.push_back(glm::vec3(smallestExtentMax.x, smallestExtentMax.y, 0.f));
285 p.push_back(glm::vec3(smallestExtentMax.x, smallestExtentMax.y, 0.f));
286 p.push_back(glm::vec3(smallestExtentMin.x, smallestExtentMax.y, 0.f));
288 p.push_back(glm::vec3(smallestExtentMin.x, smallestExtentMax.y, 0.f));
289 p.push_back(glm::vec3(smallestExtentMin.x, smallestExtentMin.y, 0.f));
298 int isBoxInsideAnyFrustum(
const std::vector<CameraState>& cameras,
const glm::vec3& boxMin,
const glm::vec3& boxMax,
const glm::vec2& nearestWorld,
const float tileNorm,
const double tileScreenCoverageThreshold)
300 bool isInsideAny =
false;
301 for (
auto & camera : cameras) {
306 for (
int i = 0; i < 8; i++) {
307 vec4 p((i & 1) ? boxMin.x : boxMax.x,
308 (i & 2) ? boxMin.y : boxMax.y,
309 (i & 4) ? boxMin.z : boxMax.z,
311 vec4 v = camera.worldToView * p;
312 vec4 c = camera.worldToClip * p;
313 planes |= (v.z < 0.f ? 1 : 0) | (-camera.farDistance <= v.z ? 2 : 0) |
314 (c.x <= c.w ? 4 : 0) | (-c.w <= c.x ? 8 : 0) |
315 (c.y <= c.w ? 16 : 0) | (-c.w <= c.y ? 32 : 0);
321 vec4 nearestView = camera.worldToView * vec4(nearestWorld, 0.f, 1.f);
322 float d = max(camera.nearDistance, -nearestView.z / nearestView.w);
323 if(camera.farDistance < d)
continue;
325 const vec3 cameraOriginWorld(camera.viewToWorld[3]);
326 const vec3 cameraZAxisWorld(camera.viewToWorld[2]);
328 vec3 tileReferenceL = cameraOriginWorld - d * normalize(cameraZAxisWorld) - tileNorm * camera.worldUnitXY;
329 vec3 tileReferenceR = cameraOriginWorld - d * normalize(cameraZAxisWorld) + tileNorm * camera.worldUnitXY;
330 vec2 tileRefNDCL = vec2(euclidean(camera.worldToClip*vec4(tileReferenceL, 1.f)));
331 vec2 tileRefNDCR = vec2(euclidean(camera.worldToClip*vec4(tileReferenceR, 1.f)));
333 vec2 tileRefScreen = camera.viewportSize * (tileRefNDCR - tileRefNDCL);
334 double tileScreenCoverage = double(tileRefScreen.x)*double(tileRefScreen.y);
336 if (tileScreenCoverageThreshold < tileScreenCoverage)
return 2;
340 return isInsideAny ? 1 : 0;
345 const std::vector<CameraState>& cameras,
346 const glm::mat4 lodRefTransform,
347 const float levelOfDetailTolerance)
349 vec3 cameraOriginWorld(lodRefTransform[3]);
351 int gridResolution = 1 << gridData.tileResolutionLog2;
356 double tileScreenCoverageThreshold = 0.25 * double(gridResolution * gridResolution * levelOfDetailTolerance);
364 while (!refineQueue.empty()) {
365 const auto & currentNode = refineQueue.front();
367 double delta = 1.0 / double(1 << currentNode.ix.level);
369 vec2 tileMinWorld = mix(gridData.currentExtentMin, gridData.currentExtentMax, delta * dvec2(currentNode.ix.xIndex, currentNode.ix.yIndex));
370 vec2 tileMaxWorld = mix(gridData.currentExtentMin, gridData.currentExtentMax, delta * dvec2(currentNode.ix.xIndex + 1, currentNode.ix.yIndex + 1));
372 float tileNorm = max(tileMaxWorld.x - tileMinWorld.x, tileMaxWorld.y - tileMinWorld.y) / gridResolution;
375 vec3 displacedTileMinWorld = vec3(tileMinWorld, 0.f) + gridComp.
displaceMin;
376 vec3 displacedTileMaxWorld = vec3(tileMaxWorld, 0.f) + gridComp.
displaceMax;
379 vec2 nearestWorld = clamp(vec2(cameraOriginWorld), tileMinWorld, tileMaxWorld);
381 auto s = isBoxInsideAnyFrustum(cameras, displacedTileMinWorld, displacedTileMaxWorld, nearestWorld, tileNorm, tileScreenCoverageThreshold);
387 uint16_t currIndex =
static_cast<uint16_t
>(quadTree.size());
388 if (currentNode.parent != NoParent) {
389 quadTree[currentNode.parent].children[currentNode.isWhichChild] = currIndex;
393 bool tileTooLarge = s == 2;
394 bool belowMaxTileLimit = leaves.size() + refineQueue.size() < size_t(maxTiles);
395 bool belowMaxLevelLimit = currentNode.ix.level + 1 < maxLevel;
397 if (belowMaxTileLimit && tileTooLarge && belowMaxLevelLimit) {
400 AdaptivePlanarGridQuadTreeNode::DeadEnd,
401 AdaptivePlanarGridQuadTreeNode::DeadEnd,
402 AdaptivePlanarGridQuadTreeNode::DeadEnd,
403 AdaptivePlanarGridQuadTreeNode::DeadEnd }
406 const uint32_t x = currentNode.ix.xIndex << 1;
407 const uint32_t y = currentNode.ix.yIndex << 1;
408 const uint8_t level = currentNode.ix.level + 1;
409 const int parent = currIndex;
419 AdaptivePlanarGridQuadTreeNode::Leaf,
420 AdaptivePlanarGridQuadTreeNode::Leaf,
421 AdaptivePlanarGridQuadTreeNode::Leaf,
422 AdaptivePlanarGridQuadTreeNode::Leaf }
425 leaves.push_back(currentNode.ix);
430 refineQueue.pop_front();
437 auto sceneComp = gridData.tileEntitiesGroup->getComponent<
SceneComponent>();
439 for (
auto & c : sceneComp->children) {
441 mshRndComp->
subMesh = gridData.camYaw;
444 auto & matData = gridData.materialData;
446 for (
size_t i = 0; i < gridData.tiles.size(); i++) {
447 auto & tile = gridData.tiles[i];
448 tile.materialInstance->setVec4Property(matData.lodLevelsKey,
449 vec4(tile.adjacentLevels[0],
450 tile.adjacentLevels[1],
451 tile.adjacentLevels[2],
452 tile.adjacentLevels[3]));
453 tile.materialInstance->setVec4Property(matData.texCoordWorldTransformKey, tile.texCoordWorldTransform);
454 tile.materialInstance->setVec4Property(matData.texCoordUnitTransformKey, tile.texCoordUnitTransform);
455 tile.materialInstance->setVec4Property(matData.texCoordLinearTransformKey, glm::make_vec4(glm::value_ptr(gridData.texCoordLinearTransform)));
461 const size_t oldSize = gridData.materialPool.size();
462 gridData.materialPool.resize(std::max(gridData.materialPool.size(), gridData.tiles.size()));
463 gridData.entityPool.resize(std::max(gridData.entityPool.size(), gridData.tiles.size()));
465 for (
size_t i = oldSize; i < gridData.materialPool.size(); ++i) {
466 gridData.materialPool[i] = context->materialInstanceManager->createMaterialInstance(gridData.materialData.material);
467 if (gridData.materialData.initMaterialInstanceCallback) {
468 gridData.materialData.initMaterialInstanceCallback(
static_cast<MaterialInstance*
>(gridData.materialPool[i].get()), container, gridData.materialData.initMaterialInstanceData);
472 for (
size_t i = oldSize; i < gridData.entityPool.size(); ++i) {
473 gridData.entityPool[i] = context->
store->
createChildEntity(
"SubMeshPart", gridData.tileEntitiesGroup.get(),
"Pooled Entity " + std::to_string(i));
474 auto entity = gridData.entityPool[i];
479 meshComp->setChanged();
483 for (
size_t i = gridData.tiles.size(); i < gridData.entityPool.size(); ++i) {
484 auto & entity = gridData.entityPool[i];
493 updatePools(context, gridComp.
getContainer(), gridData);
497 glm::vec2 unityMin = glm::vec2((gridData.currentExtentMin - gridComp.
extentMin) / fullWidth);
498 glm::vec2 unityMax = glm::vec2((gridData.currentExtentMax - gridComp.
extentMin) / fullWidth);
499 glm::dvec3 origin = context->transformSystem->
getOrigin();
501 bool originChanged = origin != gridData.currentOrigin;
502 gridData.currentOrigin = origin;
505 for (
size_t i = 0; i < gridData.tiles.size(); i++) {
506 auto & tile = gridData.tiles[i];
508 const float delta = 1.f / (1 << tile.ix.level);
509 const vec2 minLocal = delta * vec2(tile.ix.xIndex, tile.ix.yIndex);
510 const vec2 maxLocal = minLocal + delta;
512 auto & entity = gridData.entityPool[i];
513 tile.materialInstance = gridData.materialPool[i];
516 meshRendComp->
materials.resize(gridData.tessellations);
518 for (
int k = 0; k < gridData.tessellations; k++) {
519 meshRendComp->materials[k] = tile.materialInstance;
522 meshRendComp->setVisible(
true);
523 meshRendComp->layer = gridComp.
layer;
524 meshRendComp->objectId = gridData.objectId;
525 meshRendComp->subMesh = -1;
526 meshRendComp->setChanged();
528 const vec2 minWorld = mix(vec2(gridData.currentExtentMin), vec2(gridData.currentExtentMax), minLocal);
529 const vec2 maxWorld = mix(vec2(gridData.currentExtentMin), vec2(gridData.currentExtentMax), maxLocal);
530 const vec2 minUnit = mix(unityMin, unityMax, minLocal);
531 const vec2 maxUnit = mix(unityMin, unityMax, maxLocal);
534 vec3 newPosition = vec3(minWorld, 0.0);
535 vec3 newScale = vec3(maxWorld - minWorld, 1.f);
537 if (transformComponent->position != newPosition ||
538 transformComponent->scale != newScale ||
541 transformComponent->position = newPosition;
542 transformComponent->scale = newScale;
547 vec2 texCoordWorldShiftFromTilePos = gridData.texCoordLinearTransform*minWorld;
548 vec2 texCoordUnitShiftFromTilePos = gridData.texCoordLinearTransform*minUnit;
550 if (std::isfinite(gridData.texCoordPeriod.x)) {
551 texCoordWorldShiftFromTilePos.x = glm::mod(texCoordWorldShiftFromTilePos.x, gridData.texCoordPeriod.x);
552 texCoordUnitShiftFromTilePos.x = glm::mod(texCoordUnitShiftFromTilePos.x, gridData.texCoordPeriod.x);
554 if (std::isfinite(gridData.texCoordPeriod.y)) {
555 texCoordWorldShiftFromTilePos.y = glm::mod(texCoordWorldShiftFromTilePos.y, gridData.texCoordPeriod.y);
556 texCoordUnitShiftFromTilePos.y = glm::mod(texCoordUnitShiftFromTilePos.y, gridData.texCoordPeriod.y);
559 tile.texCoordWorldTransform = vec4(maxWorld - minWorld, texCoordWorldShiftFromTilePos);
560 tile.texCoordUnitTransform = vec4(maxUnit - minUnit, texCoordUnitShiftFromTilePos);
562 const auto worldBox0 = glm::vec3(minWorld, 0) + gridComp.
displaceMin;
563 const auto worldBox1 = glm::vec3(maxWorld, 0) + gridComp.
displaceMax;
564 vec3 rootBox0(std::numeric_limits<float>::max());
565 vec3 rootBox1(-std::numeric_limits<float>::max());
566 for (
int ii = 0; ii < 8; ii++) {
567 glm::bvec3 end((ii & 1) != 0,
570 const auto ch = worldToRoot * vec4(mix(worldBox0, worldBox1, end), 1.f);
571 const auto c = (1.f / ch.w)*vec3(ch);
572 rootBox0 = min(rootBox0, c);
573 rootBox1 = max(rootBox1, c);
576 Cogs::Geometry::BoundingBox box{ rootBox0, rootBox1 };
577 context->subMeshRenderSystem->setBounds(renderComponent, box, context->transformSystem->getLocalToWorld(transformComponent));
583 if (gridData.tileResolutionLog2 == tileResolutionLog2)
return;
585 gridData.gridMesh = context->meshManager->create();
586 gridData.tileResolutionLog2 = tileResolutionLog2;
587 const int gridResolution = 1 << tileResolutionLog2;
589 vector<Triangle> T(2 * gridResolution * gridResolution);
590 ivec2 indices[2][2][3] = {
591 { { ivec2(0, 0), ivec2(1, 0), ivec2(0, 1) }, { ivec2(1, 0), ivec2(1, 1), ivec2(0, 1) } },
592 { { ivec2(0, 0), ivec2(1, 0), ivec2(1, 1) }, { ivec2(0, 0), ivec2(1, 1), ivec2(0, 1) } }
596 vector<uint32_t> I(2 * 3 * gridResolution * gridResolution);
597 for (
int d = 0; d < gridData.tessellations; d++) {
598 const float theta = (2.0f * glm::pi<float>() * d) /
float(gridData.tessellations);
599 vec2 dir(cos(theta), sin(theta));
600 int e = abs(dot(vec2(1, 1), dir)) < abs(dot(vec2(-1, 1), dir)) ? 1 : 0;
601 for (
int j = 0; j < gridResolution; j++) {
602 for (
int i = 0; i < gridResolution; i++) {
603 for (
int t = 0; t < 2; t++) {
605 for (
int k = 0; k < 3; k++) {
606 ivec2 p = ivec2(i, j) + indices[e][t][k];
608 T[2 * (j*gridResolution + i) + t].ix[k] = p.y*(gridResolution + 1) + p.x;
610 T[2 * (j*gridResolution + i) + t].key = dot(dir, key);
614 sort(T.begin(), T.end(), [](
const Triangle& a,
const Triangle& b) ->bool { return a.key > b.key; });
615 for (
size_t i = 0; i < T.size(); i++) {
616 I[3 * i + 0] = T[i].ix[0];
617 I[3 * i + 1] = T[i].ix[1];
618 I[3 * i + 2] = T[i].ix[2];
623 vec2 s(1.f / gridResolution, 1.f / gridResolution);
624 auto vertices = gridData.gridMesh->
mapPositions(0, (gridResolution + 1)*(gridResolution + 1));
625 for (
int j = 0; j <= gridResolution; j++) {
626 for (
int i = 0; i <= gridResolution; i++) {
628 if (j == 0) { edge = 3 + (i < gridResolution / 2 ? 0.f : 0.5f); }
629 else if (j == gridResolution) { edge = 4 + (i < gridResolution / 2 ? 0.f : 0.5f); }
630 else if (i == 0) { edge = 1 + (j < gridResolution / 2 ? 0.f : 0.5f); }
631 else if (i == gridResolution) { edge = 2 + (j < gridResolution / 2 ? 0.f : 0.5f); }
632 vertices[(gridResolution + 1)*j + i].x = s.x*i;
633 vertices[(gridResolution + 1)*j + i].y = s.y*j;
634 vertices[(gridResolution + 1)*j + i].z = edge;
638 gridData.gridMesh->
setBounds(Cogs::Geometry::BoundingBox{ { 0.f, 0.f, 0.f },{ 1.0f, 1.0f, 1.0f } });
647 gridData.proxyMesh = context->meshManager->create();
648 vector<uint32_t> I(1);
651 gridData.proxyMesh->
setBounds(Cogs::Geometry::BoundingBox{ { 0.f, 0.f, 0.f },{ 1.f, 1.f, 1.f } });
655 meshComponent->
meshHandle = gridData.proxyMesh;
656 meshComponent->setChanged();
663 gridData.debugMesh = context->meshManager->create();
665 matComp->diffuseColor = vec4(1.f, 0.f, 0.f, 1.f);
666 matComp->enableLighting =
false;
671 gridData.tiles.clear();
672 gridData.tiles.reserve(leaves.size());
674 for (
size_t i = 0; i < leaves.size(); i++) {
678 int levelSize = 1 << leaf.level;
688 for (
int e = 0; e < 4; e++) {
689 int xIndex = int(leaf.xIndex) + shifts[e][0];
690 int yIndex = int(leaf.yIndex) + shifts[e][1];
691 int edgeLevel = leaf.level;
693 if ((0 <= xIndex) && (xIndex < levelSize) && (0 <= yIndex) && (yIndex < levelSize)) {
696 int currQuadNode = 0;
697 while (currLevel < maxLevel) {
699 if (currQuadNode == AdaptivePlanarGridQuadTreeNode::DeadEnd) {
703 else if (currQuadNode == AdaptivePlanarGridQuadTreeNode::Leaf) {
705 edgeLevel = currLevel - 1;
710 if (currLevel == leaf.level) {
721 int currBit = leaf.level - currLevel - 1;
722 int whichChild = 2 * ((yIndex >> currBit) & 1) + ((xIndex >> currBit) & 1);
723 currQuadNode = quadTree[currQuadNode].children[whichChild];
728 edgeLevels[e] = max(0, 5 - max(0, leaf.level - edgeLevel));
732 uint8_t(edgeLevels[0]),
733 uint8_t(edgeLevels[1]),
734 uint8_t(edgeLevels[2]),
735 uint8_t(edgeLevels[3]) },
758void Cogs::Core::AdaptivePlanarGridSystem::registerMaterial(
const AdaptivePlanarGridComponent * gridComp,
MaterialHandle material, AdaptivePlanarGridMaterialData::InitMaterialInstanceCallback * initMaterialInstanceCallback,
void * initMaterialInstanceData)
760 auto & gridData = getData(gridComp);
762 auto & materialData = gridData.materialData;
764 materialData.material = material;
765 materialData.lodLevelsKey = material->getVec4Key(
"lodLevels");
766 materialData.texCoordWorldTransformKey = material->getVec4Key(
"texCoordWorldTransform");
767 materialData.texCoordUnitTransformKey = material->getVec4Key(
"texCoordUnitTransform");
768 materialData.texCoordLinearTransformKey = material->getVec4Key(
"texCoordLinearTransform");
769 materialData.initMaterialInstanceCallback = initMaterialInstanceCallback;
770 materialData.initMaterialInstanceData = initMaterialInstanceData;
773 for (
auto & item : gridData.materialPool) {
774 item =
context->materialInstanceManager->createMaterialInstance(gridData.materialData.material);
775 if (initMaterialInstanceCallback) {
776 initMaterialInstanceCallback(
static_cast<MaterialInstance*
>(item.get()), container, initMaterialInstanceData);
782void Cogs::Core::AdaptivePlanarGridSystem::setTexCoordTransform(
const AdaptivePlanarGridComponent * gridComp,
const glm::mat2 transform,
const glm::vec2 period)
784 auto & gridData = getData(gridComp);
785 gridData.texCoordLinearTransform = transform;
786 gridData.texCoordPeriod = period;
792 for (
const auto & gridComp : pool) {
798 lodRefTrComp = context->cameraSystem->getMainCamera()->getComponent<
TransformComponent>();
800 if(!lodRefTrComp)
continue;
802 std::vector<CameraComponent*> cameraComps;
803 for (
auto & weak : gridComp.
cameras) {
804 if (
auto entity = weak.lock(); entity) {
807 cameraComps.push_back(comp);
813 if (cameraComps.empty()) {
816 cameraComps.push_back(comp);
820 auto * mcomp = context->cameraSystem->getMainCamera();
822 cameraComps.push_back(mcomp);
827 auto & gridData = getData(&gridComp);
828 if (!gridData.initialized) {
830 setupProxyMesh(context, gridComp, gridData);
831 setupDebugMesh(context, gridComp, gridData);
836 if (renderComponent) {
837 gridData.objectId = renderComponent->objectId;
840 gridData.initialized =
true;
850 const glm::mat4 worldToRoot = context->transformSystem->getLocalToWorld(trComp);
851 const glm::mat4 rootToWorld = glm::inverse(worldToRoot);
857 std::vector<CameraState> cameras;
858 for (
size_t i = 0; i < cameraComps.size(); i++) {
859 auto * camComp = cameraComps[i];
860 auto & camData = context->cameraSystem->getData(camComp);
861 if (camData.viewportSize.x < 1.f || camData.viewportSize.y < 1.f)
continue;
871 const glm::mat4& inverseViewMatrix = context->transformSystem->getLocalToWorld(camTrComp);
872 const glm::mat4 viewMatrix = glm::inverse(inverseViewMatrix);
875 cameras.emplace_back(CameraState());
876 auto & c = cameras.back();
879 c.worldToView = viewMatrix * worldToRoot;
880 c.worldToClip = camData.projectionMatrix * c.worldToView;
881 c.viewToWorld = rootToWorld * inverseViewMatrix;
882 c.worldUnitXY = normalize(vec3(c.viewToWorld[0])) + normalize(vec3(c.viewToWorld[1]));
883 c.viewportSize = camData.viewportSize;
884 c.nearDistance = camComp->nearDistance;
885 c.farDistance = camComp->enableClippingPlaneAdjustment ? std::numeric_limits<float>::max() : camComp->farDistance;
889 if (!gridData.materialData.material)
continue;
891 if(!cameras.empty()) {
896 const mat4 & viewToWorld = context->transformSystem->getLocalToWorld(lodRefTrComp);
897 if (std::isfinite(viewToWorld[2].x) && std::isfinite(viewToWorld[2].y)) {
898 const float theta = (float(gridData.tessellations) / (2.0f * glm::pi<float>())) * std::atan2(viewToWorld[2].y, viewToWorld[2].x);
899 gridData.camYaw = max(0, min(gridData.tessellations - 1,
int(round(theta + 0.5f * gridData.tessellations))));
905 analyzeView(context, gridComp, gridData, cameras,
false);
906 refineTiles(gridComp, gridData, cameras, viewToWorld, lodComponent->geometricTolerance);
907 updateTileTopology(gridData);
908 updateTileEntities(context, gridComp, gridData, worldToRoot);
913 auto meshComp = gridData.debugGraphics->getComponent<
MeshComponent>();
914 if (meshComp->meshHandle) {
922 auto meshComp = gridData.debugGraphics->getComponent<
MeshComponent>();
924 if (!meshComp->meshHandle) {
927 analyzeView(context, gridComp, gridData, cameras,
true);
931 updateTileMaterialInstances(gridComp, gridData);
void setChanged()
Sets the component to the ComponentFlags::Changed state with carry.
ComponentType * getComponent() const
class Entity * getContainer() const
Get the container currently owning this component instance.
Container for components, providing composition of dynamic entities.
T * getComponent() const
Get a pointer to the first component implementing the given type in the entity.
bool debugGeometry
Enable creation of miscellaneous debug geometry, like the intersected frustum and so on.
bool updateLoD
Enable/disable updates of level-of-detail hierarchy.
glm::vec3 displaceMin
Minimum corner of vertex displacement. Forwarded to misc bounding boxes.
glm::vec3 displaceMax
Maximum corner of vertex displacement. Forwarded to misc bounding boxes.
WeakEntityPtr lodReference
Entity to use as center reference to level of detail calculations, defaults to main camera.
glm::dvec2 extentMax
Maximum corner of extent to cover.
int tileResolutionLog2
Internal resolution of each tile in the grid.
RenderLayers layer
Layer used to render tiles.
std::vector< WeakEntityPtr > cameras
List of cameras for which frustums will be used to deduce visible geometry, defaults to main camera.
glm::dvec2 extentMin
Minimum corner of extent to cover.
Context * context
Pointer to the Context instance the system lives in.
void update()
Updates the system state to that of the current frame.
Component system with parallel data per component stored in a pool similar to how the components them...
A Context instance contains all the services, systems and runtime components needed to use Cogs.
class EntityStore * store
Entity store.
EntityPtr createChildEntity(const StringView &type, ComponentModel::Entity *parent, const StringView &name=StringView())
Create a new Entity, parenting it to the given parent.
Contains data describing level of detail behavior for the entity the component belongs to.
Contains a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
MeshHandle meshHandle
Handle to a Mesh resource to use when rendering.
Base component for all rendering content.
constexpr void setVisible(bool visible)
Set the specific visibility.
Contains information on how the entity behaves in the scene.
Renders a mesh with flexible submesh usage.
std::vector< MaterialInstanceHandle > materials
Materials used to render individual sub-meshes.
int subMesh
Sub mesh index.
Log implementation class.
Base allocator implementation.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
COGSCORE_DLL_API SimplexResult simplexMaximize(Context *context, uintptr_t scratch, double *solutions, const int variableCount, const double *objectives, const int objectiveCount, const double *restrictions, const int restrictionCount, const int maxIterationCount, const bool printSteps=false)
Find the maximum of a linear programming problem using the simplex method.
@ EnableRender
Renderable.
COGSCORE_DLL_API size_t simplexScratchSize(const size_t variableCount, const size_t objectiveCount, const size_t restrictionCount)
Number of bytes of scratch array required by simplexMaximize.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
ComponentIndex SizeType
Type used to track the size of pools.
Exposes material properties for legacy entities and code.
Material instances represent a specialized Material combined with state for all its buffers and prope...
void setBounds(Geometry::BoundingBox box)
Set custom bounds for the mesh.
void clearIndexes()
Clear all index data, also clearing all sub-meshes.
MappedStream< glm::vec3 > mapPositions(const size_t start, const size_t end)
Map the position stream for write access, range between start and end.
void addSubMesh(std::span< uint32_t > collection, PrimitiveType::EPrimitiveType primitiveType)
Add a sub-mesh to the Mesh.
void setPositions(std::span< const glm::vec3 > positions)
Set the position data of the Mesh.
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
@ TriangleList
List of triangles.