From aaa7b1e24ebd3055784310075416b6fc670f9114 Mon Sep 17 00:00:00 2001 From: yggdrasil75 Date: Wed, 28 Jan 2026 21:00:16 -0500 Subject: [PATCH] preparations for further changes --- tests/g3etest.cpp | 110 ++++++++++++++++++++++++++------------- util/grid/camera.hpp | 2 + util/grid/grid3eigen.hpp | 35 ++++++++----- 3 files changed, 99 insertions(+), 48 deletions(-) diff --git a/tests/g3etest.cpp b/tests/g3etest.cpp index 02a5056..372f9ff 100644 --- a/tests/g3etest.cpp +++ b/tests/g3etest.cpp @@ -38,8 +38,9 @@ struct spheredefaults { float emittance = 0.0f; float reflection = 0.0f; float refraction = 0.0f; - bool fillInside = true; - float voxelSize = 10.0f; + bool fillInside = false; + float voxelSize = 1.5f; + int numPoints = 15000; }; struct ceilingdefaults { @@ -64,41 +65,63 @@ using PointType = Eigen::Matrix; void createSphere(const defaults& config, const spheredefaults& sconfig, Octree& grid) { if (!grid.empty()) grid.clear(); - int minX = std::max(0, (int)(sconfig.centerX - sconfig.radius - 1)); - int maxX = std::min(config.gridSizecube, (int)(sconfig.centerX + sconfig.radius + 1)); - int minY = std::max(0, (int)(sconfig.centerY - sconfig.radius - 1)); - int maxY = std::min(config.gridSizecube, (int)(sconfig.centerY + sconfig.radius + 1)); - int minZ = std::max(0, (int)(sconfig.centerZ - sconfig.radius - 1)); - int maxZ = std::min(config.gridSizecube, (int)(sconfig.centerZ + sconfig.radius + 1)); - - float radSq = sconfig.radius * sconfig.radius; - float innerRadSq = 0.0f; - if (!sconfig.fillInside) { - float innerR = std::max(0.0f, sconfig.radius - 2.0f); - innerRadSq = innerR * innerR; - } - + + float phi = M_PI * (3.0f - std::sqrt(5.0f)); // Golden angle in radians Eigen::Vector3f colorVec(sconfig.color[0], sconfig.color[1], sconfig.color[2]); - for (int x = minX; x < maxX; ++x) { - for (int y = minY; y < maxY; ++y) { - for (int z = minZ; z < maxZ; ++z) { - float dx = x - sconfig.centerX; - float dy = y - sconfig.centerY; - float dz = z - sconfig.centerZ; - float distSq = dx*dx + dy*dy + dz*dz; + + // We treat sconfig.voxelSize as an overlap multiplier. + // 1.0 gives mathematical coverage, >1.0 ensures overlap for solidity. + float overlapMultiplier = std::max(0.1f, sconfig.voxelSize); - bool solid = distSq <= radSq; + float currentRadius = sconfig.radius; + + // Loop for shells. If fillInside is false, this loop runs once. + // If true, it runs until radius is negligible. + while (currentRadius > 0.5f) { + // To maintain uniform visual density, the number of points on an inner shell + // should be proportional to surface area (radius^2). + float scaleFactor = currentRadius / sconfig.radius; + int currentN = std::max(4, (int)(sconfig.numPoints * scaleFactor * scaleFactor)); + + // Calculate the point radius required to fully cover the surface area of the sphere. + // Surface Area = 4 * PI * R^2. + // Area per point = Surface Area / N. + // Approximate point radius r: PI * r^2 = Area per point. + // r = sqrt(4 * R^2 / N) = 2 * R / sqrt(N). + float calculatedSize = (2.0f * currentRadius) / std::sqrt((float)currentN); + + // Apply user-defined multiplier for extra solidity/overlap + float finalSize = calculatedSize * overlapMultiplier * overlapMultiplier; + + for (int i = 0; i < currentN; ++i) { + // Fibonacci Sphere math + float y = 1.0f - (i / (float)(currentN - 1)) * 2.0f; // y goes from 1 to -1 + float radiusAtY = std::sqrt(1.0f - y * y); // Radius at this height + float theta = phi * i; // Golden angle increment + + float x = std::cos(theta) * radiusAtY; + float z = std::sin(theta) * radiusAtY; + + PointType pos( + sconfig.centerX + x * currentRadius, + sconfig.centerY + y * currentRadius, + sconfig.centerZ + z * currentRadius + ); + + // Boundary check to prevent segfaults if radius pushes out of grid bounds + if (pos.x() >= 0 && pos.x() < config.gridSizecube && + pos.y() >= 0 && pos.y() < config.gridSizecube && + pos.z() >= 0 && pos.z() < config.gridSizecube) { - if (solid) { - if (!(sconfig.fillInside) && distSq < innerRadSq) { - continue; - } - - PointType pos((float)x, (float)y, (float)z); - grid.set(1,pos, true, colorVec, sconfig.voxelSize, true, sconfig.light, sconfig.emittance, sconfig.refraction, sconfig.reflection); - } + grid.set(1, pos, true, colorVec, finalSize, true, + sconfig.light, sconfig.emittance, sconfig.refraction, sconfig.reflection); } } + + if (!sconfig.fillInside) break; + + // Decrease radius by a fraction of the point size to ensure shells overlap + currentRadius -= (finalSize * 0.75f); } } @@ -122,7 +145,7 @@ void addCeilingLight(const defaults& config, const ceilingdefaults& ceilingconf, void livePreview(Octree& grid, defaults& config, const Camera& cam) { std::lock_guard lock(PreviewMutex); updatePreview = true; - frame currentPreviewFrame = grid.renderFrame(cam, config.outWidth, config.outHeight, frame::colormap::RGB); + frame currentPreviewFrame = grid.renderFrame(cam, config.outWidth, config.outHeight, frame::colormap::RGB, 4, 3); glGenTextures(1, &textu); glBindTexture(GL_TEXTURE_2D, textu); @@ -217,9 +240,13 @@ int main() { Octree grid(minBound, maxBound, 16, 16); bool gridInitialized = false; float ghalf = config.gridSizecube / 2.f; - Camera cam(PointType(ghalf, ghalf, ghalf), PointType(0,0,1), PointType(0,1,0), 80); + spheredefaults sphereConf; ceilingdefaults ceilingConf; + + sphereConf.centerX = ghalf; + sphereConf.centerY = ghalf; + sphereConf.centerZ = ghalf; bool autoRotate = false; bool autoRotateView = false; @@ -241,6 +268,7 @@ int main() { float camvY = 0.f; float camvZ = 0.f; float camspeed = 50; + Camera cam(PointType(400, 400, 400), PointType(0,0,1), PointType(0,1,0), 80, camspeed); // Keyboard state tracking std::map keyStates; @@ -253,6 +281,9 @@ int main() { static double lastFrameTime = currentTime; deltaTime = currentTime - lastFrameTime; lastFrameTime = currentTime; + + if (autoRotate) autoRotationTime += deltaTime; + if (autoRotateView) autoRotationAngle += deltaTime; glfwPollEvents(); @@ -315,7 +346,7 @@ int main() { { ImGui::Begin("Controls"); - ImGui::Text("Sphere Parameters"); + ImGui::Text("Planet"); float pos[3] = { sphereConf.centerX, sphereConf.centerY, sphereConf.centerZ }; if (ImGui::DragFloat3("Center (X,Y,Z)", pos, 1.0f, 0.0f, (float)config.gridSizecube)) { sphereConf.centerX = pos[0]; @@ -324,8 +355,15 @@ int main() { } ImGui::DragFloat("Radius", &sphereConf.radius, 0.5f, 1.0f, 250.0f); + + // Replaced traditional voxel sizing with Point Count logic + ImGui::DragInt("Point Count", &sphereConf.numPoints, 100, 100, 200000); + ImGui::DragFloat("Density (Overlap)", &sphereConf.voxelSize, 0.05f, 0.1f, 5.0f); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Multiplies calculated point size. >1.0 ensures solid surface."); + } + ImGui::ColorEdit3("Color", sphereConf.color); - ImGui::DragFloat("Voxel Size", &sphereConf.voxelSize, 0.1f, 0.1f, 5.0f); ImGui::Separator(); ImGui::Checkbox("Is Light", &sphereConf.light); diff --git a/util/grid/camera.hpp b/util/grid/camera.hpp index dbb239b..135b5fc 100644 --- a/util/grid/camera.hpp +++ b/util/grid/camera.hpp @@ -15,6 +15,8 @@ struct Camera { float fov; float movementSpeed; float rotationSpeed; + + Camera() : origin(Vector3f(0,0,0)), direction(Vector3f(0,0,0)), up(Vector3f(0,0,0)), fov(80), movementSpeed(10), rotationSpeed(10) {} Camera(const Vector3f& pos, const Vector3f& viewdir, const Vector3f& up, float fov = 80, float moveSpeed = 1.0f, float rotSpeed = 0.5f) diff --git a/util/grid/grid3eigen.hpp b/util/grid/grid3eigen.hpp index 9d776d3..9fed656 100644 --- a/util/grid/grid3eigen.hpp +++ b/util/grid/grid3eigen.hpp @@ -21,7 +21,6 @@ #endif constexpr int Dim = 3; -constexpr int maxBounces = 4; template class Octree { @@ -384,7 +383,13 @@ private: float x = randomValueNormalDistribution(state); float y = randomValueNormalDistribution(state); float z = randomValueNormalDistribution(state); - return PointType(x,y,z).normalized(); + PointType randomDir(x, y, z); + randomDir.normalize(); + + if (randomDir.dot(normal) < 0.0f) { + randomDir = -randomDir; + } + return randomDir; } float rgbToGrayscale(const Eigen::Vector3f& color) const { @@ -413,7 +418,7 @@ public: std::ofstream out(filename, std::ios::binary); if (!out) return false; - uint32_t magic = 0x79676733; + uint32_t magic = 0x79676733; writeVal(out, magic); writeVal(out, maxDepth); writeVal(out, maxPointsPerNode); @@ -435,7 +440,7 @@ public: uint32_t magic; readVal(in, magic); - if (magic != 0x0C78E3) { + if (magic != 0x79676733) { std::cerr << "Invalid Octree file format" << std::endl; return false; } @@ -466,6 +471,8 @@ public: if (!node || tMin > tMax) return; if (node->isLeaf) { for (const auto& pointData : node->points) { + if (!pointData->active) continue; + PointType toPoint = pointData->position - origin; float projection = toPoint.dot(dir); if (projection >= 0 && projection <= maxDist) { @@ -517,7 +524,7 @@ public: return hits; } - frame renderFrame(const Camera& cam, int height, int width, frame::colormap colorformat = frame::colormap::RGB) { + frame renderFrame(const Camera& cam, int height, int width, frame::colormap colorformat = frame::colormap::RGB, int samplesPerPixel = 2, int maxBounces = 4) { PointType origin = cam.origin; PointType dir = cam.direction.normalized(); PointType up = cam.up.normalized(); @@ -549,7 +556,7 @@ public: if (bounces > maxBounces) return {0,0,0}; auto hits = voxelTraverse(rayOrig, rayDir, rayLength, true); - if (hits.empty() && bounces < 1) { + if (hits.empty() && bounces == 0) { return defaultColor; } else if (hits.empty()) { return {0,0,0}; @@ -626,21 +633,26 @@ public: #pragma omp parallel for schedule(dynamic) collapse(2) for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { + int pidx = (y * width + x); + uint32_t seed = pidx * 1973 + 9277; + int idx = pidx * channels; + float px = (2.0f * (x + 0.5f) / width - 1.0f) * tanfovx; float py = (1.0f - 2.0f * (y + 0.5f) / height) * tanfovy; PointType rayDir = dir + (right * px) + (up * py); rayDir.normalize(); + + Eigen::Vector3f accumulatedColor(0.0f, 0.0f, 0.0f); - int pidx = (y * width + x); - uint32_t seed = pidx * 1973 + 9277; - int idx = pidx * channels; + for(int s = 0; s < samplesPerPixel; ++s) { + accumulatedColor += traceRay(origin, rayDir, 0, seed); + } - Eigen::Vector3f color = traceRay(origin, rayDir, 0, seed); + Eigen::Vector3f color = accumulatedColor / static_cast(samplesPerPixel); color = color.cwiseMax(0.0f).cwiseMin(1.0f); - switch(colorformat) { case frame::colormap::B: colorBuffer[idx ] = static_cast(rgbToGrayscale(color) * 255.0f); @@ -667,7 +679,6 @@ public: colorBuffer[idx + 2] = static_cast(color[0] * 255.0f); colorBuffer[idx + 3] = 255; break; - } } }