diff --git a/tests/planet.cpp b/tests/planet.cpp index a40eac0..b8af6b2 100644 --- a/tests/planet.cpp +++ b/tests/planet.cpp @@ -167,6 +167,9 @@ public: if (ImGui::CollapsingHeader("Celestial Bodies")) { ///TODO: add controls for moon, star. + if (ImGui::Button("Add Star", ImVec2(-1, 40))) { + sim.addStar(); + } } if (ImGui::CollapsingHeader("Fillings")) { diff --git a/util/grid/grid3eigen.hpp b/util/grid/grid3eigen.hpp index 8664fdd..99c0155 100644 --- a/util/grid/grid3eigen.hpp +++ b/util/grid/grid3eigen.hpp @@ -235,7 +235,7 @@ private: float lodFalloffRate_ = 0.1f; // Lower = better, higher = worse. 0-1 float lodMinDistance_ = 100.0f; - float maxDistance_ = 4096; + float maxDistance_ = size * size; struct Ray { PointType origin; @@ -339,7 +339,11 @@ private: } else { bool inserted = false; for (int i = 0; i < 8; ++i) { - if (node->children[i] && boxIntersectsBox(node->children[i]->bounds, cubeBounds)) { + BoundingBox childBounds = createChildBounds(node, i); + if (boxIntersectsBox(childBounds, cubeBounds)) { + if (!node->children[i]) { + node->children[i] = std::make_unique(childBounds.first, childBounds.second); + } inserted |= insertRecursive(node->children[i].get(), pointData, depth + 1); } } @@ -369,6 +373,56 @@ private: } } + void ensureBounds(const BoundingBox& targetBounds) { + if (!root_) { + PointType center = (targetBounds.first + targetBounds.second) * 0.5f; + PointType size = targetBounds.second - targetBounds.first; + float maxDim = size.maxCoeff(); + if (maxDim <= 0.0f) maxDim = 1.0f; + PointType halfSize = PointType::Constant(maxDim * 0.5f); + root_ = std::make_unique(center - halfSize, center + halfSize); + return; + } + + while (true) { + bool xInside = root_->bounds.first.x() <= targetBounds.first.x() && root_->bounds.second.x() >= targetBounds.second.x(); + bool yInside = root_->bounds.first.y() <= targetBounds.first.y() && root_->bounds.second.y() >= targetBounds.second.y(); + bool zInside = root_->bounds.first.z() <= targetBounds.first.z() && root_->bounds.second.z() >= targetBounds.second.z(); + + if (xInside && yInside && zInside) { + break; + } + + PointType min = root_->bounds.first; + PointType max = root_->bounds.second; + PointType size = max - min; + + int expandX = (targetBounds.first.x() < min.x()) ? -1 : 1; + int expandY = (targetBounds.first.y() < min.y()) ? -1 : 1; + int expandZ = (targetBounds.first.z() < min.z()) ? -1 : 1; + + PointType newMin = min; + PointType newMax = max; + + if (expandX < 0) newMin.x() -= size.x(); else newMax.x() += size.x(); + if (expandY < 0) newMin.y() -= size.y(); else newMax.y() += size.y(); + if (expandZ < 0) newMin.z() -= size.z(); else newMax.z() += size.z(); + + auto newRoot = std::make_unique(newMin, newMax); + newRoot->isLeaf = false; + + uint8_t oldOctant = 0; + if (expandX < 0) oldOctant |= 1; + if (expandY < 0) oldOctant |= 2; + if (expandZ < 0) oldOctant |= 4; + + newRoot->children[oldOctant] = std::move(root_); + root_ = std::move(newRoot); + + maxDepth++; + } + } + void ensureLOD(OctreeNode* node) { std::lock_guard lock(node->lodMutex); if (node->lodData != nullptr) return; @@ -1276,6 +1330,8 @@ public: auto pointData = std::make_shared(data, pos, visible, cIdx, size, active, objectId, subId, mIdx); + ensureBounds(pointData->getCubeBounds()); + if (insertRecursive(root_.get(), pointData, 0)) { this->size++; return true; @@ -1478,6 +1534,7 @@ public: } if (matChanged) pointData->materialIdx = getMaterialIndex(mat); + ensureBounds(pointData->getCubeBounds()); bool res = insertRecursive(root_.get(), pointData, 0); if(res) { @@ -1496,6 +1553,7 @@ public: removeRecursive(root_.get(), pointData->getCubeBounds(), pointData); pointData->position = newPos; + ensureBounds(pointData->getCubeBounds()); if (insertRecursive(root_.get(), pointData, 0)) { return true; @@ -2118,10 +2176,17 @@ public: collectNodesByObjectId(root_.get(), objectId, nodes); if(nodes.empty()) return false; - for(auto& n : nodes) remove(n->position); + for(auto& n : nodes) { + if (removeRecursive(root_.get(), n->getCubeBounds(), n)) { + size--; + } + } for(auto& n : nodes) { n->position += offset; - insertRecursive(root_.get(), n, 0); + ensureBounds(n->getCubeBounds()); + if (insertRecursive(root_.get(), n, 0)) { + size++; + } } for (auto& [key, mesh] : meshCache_) { diff --git a/util/sim/planet.hpp b/util/sim/planet.hpp index 8ef7407..80e9bf7 100644 --- a/util/sim/planet.hpp +++ b/util/sim/planet.hpp @@ -26,7 +26,7 @@ #include "../stb/stb_image.h" using v3 = Eigen::Vector3f; -using v3half = Eigen::Matrix; // 16-bit vector alias +using v3half = Eigen::Matrix; const float Φ = M_PI * (3.0f - std::sqrt(5.0f)); enum class PlateType { @@ -149,7 +149,7 @@ struct planetConfig { float maxElevationRatio = 0.25f; float gridSizeCube = 65536; //absolute max size for all nodes - float gridSizeCubeMin = 16384; //max size, if something leaves this, then it probably needs to be purged before it leaves the grid and becomes lost + float gridSizeCubeMin = 4096; //max size, if something leaves this, then it probably needs to be purged before it leaves the grid and becomes lost float SMOOTHING_RADIUS = 1024.0f; float REST_DENSITY = 0.00005f; float TIMESTEP = 0.016f; @@ -184,7 +184,7 @@ public: planetsim() { config = planetConfig(); - grid = Octree(v3(-config.gridSizeCube,-config.gridSizeCube,-config.gridSizeCube),v3(config.gridSizeCube,config.gridSizeCube,config.gridSizeCube), 16, 32); + grid = Octree(v3(-config.gridSizeCubeMin,-config.gridSizeCubeMin,-config.gridSizeCubeMin),v3(config.gridSizeCubeMin,config.gridSizeCubeMin,config.gridSizeCubeMin), 16, 32); } float evaluate2DStack(const Eigen::Vector2f& point, const NoisePreviewState& state, PNoise2& gen) { @@ -255,7 +255,7 @@ public: } config.currentStep = 1; std::cout << "Step 1 done. base sphere generated" << std::endl; - grid.save("output/fibSphere"); + grid.save("output/fibSphere.yggs"); } inline void _applyNoise(std::function noiseFunc) { @@ -776,10 +776,66 @@ public: } grid.optimize(); std::cout << "Finalize apply results completed." << std::endl; + grid.save("output/plateworld.yggs"); } void addStar() { - ///TODO: add a star at roughly earth distance scaled based on planet radius. + TIME_FUNCTION; + + const float realEarthRadiusKm = 6371.0f; + const float realSunRadiusKm = 696340.0f; + const float realAuKm = 149597870.0f; + float simScale = config.radius / realEarthRadiusKm; + + float starRadius = realSunRadiusKm * simScale; + float orbitDistance = realAuKm * simScale; + + std::cout << "--- STAR GENERATION ---" << std::endl; + std::cout << "Sim Scale: " << simScale << " units/km" << std::endl; + std::cout << "Star Radius: " << starRadius << " units" << std::endl; + std::cout << "Orbit Distance: " << orbitDistance << " units" << std::endl; + + if (orbitDistance > config.gridSizeCube) { + std::cout << "[WARNING] Star distance (" << orbitDistance + << ") exceeds octree bounds (" << config.gridSizeCube + << "). Please increase gridSizeCube or the star will be outside the grid!" << std::endl; + } + + v3 starCenter = config.center + v3(orbitDistance, 0.0f, 0.0f); + v3 starColor = v3(1.0f, 0.95f, 0.8f); + + int starPoints = config.surfacePoints * 10; + + for (int i = 0; i < starPoints; i++) { + float y = 1.0f - (i * 2.0f) / (starPoints - 1); + float radiusY = std::sqrt(1.0f - y * y); + float Θ = Φ * i; + float x = std::cos(Θ) * radiusY; + float z = std::sin(Θ) * radiusY; + + v3 dir(x, y, z); + v3 pos = starCenter + dir * starRadius; + Particle pt; + + pt.altPos = std::make_unique(); + pt.altPos->originalPos = pos.cast(); + pt.altPos->noisePos = pos.cast(); + pt.altPos->tectonicPos = pos.cast(); + + pt.currentPos = pos; + pt.originColor = starColor.cast(); + pt.noiseDisplacement = 0.0f; + pt.surface = true; + pt.plateID = -2; + + config.surfaceNodes.emplace_back(pt); + + grid.set(pt, pt.currentPos, true, pt.originColor.cast(), config.voxelSize, true, 2, 0, 1.0, 0.0f, 0.0f, 1.0f); + } + + grid.optimize(); + config.currentStep = 1; + std::cout << "Star generation complete. Placed " << starPoints << " nodes." << std::endl; } void addMoon() {