preparations for further changes

This commit is contained in:
yggdrasil75
2026-01-28 21:00:16 -05:00
parent f24fcaa691
commit aaa7b1e24e
3 changed files with 99 additions and 48 deletions

View File

@@ -38,8 +38,9 @@ struct spheredefaults {
float emittance = 0.0f; float emittance = 0.0f;
float reflection = 0.0f; float reflection = 0.0f;
float refraction = 0.0f; float refraction = 0.0f;
bool fillInside = true; bool fillInside = false;
float voxelSize = 10.0f; float voxelSize = 1.5f;
int numPoints = 15000;
}; };
struct ceilingdefaults { struct ceilingdefaults {
@@ -64,41 +65,63 @@ using PointType = Eigen::Matrix<float, 3, 1>;
void createSphere(const defaults& config, const spheredefaults& sconfig, Octree<int>& grid) { void createSphere(const defaults& config, const spheredefaults& sconfig, Octree<int>& grid) {
if (!grid.empty()) grid.clear(); 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]); 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;
bool solid = distSq <= radSq; // 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);
if (solid) { float currentRadius = sconfig.radius;
if (!(sconfig.fillInside) && distSq < innerRadSq) {
continue; // 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) {
grid.set(1, pos, true, colorVec, finalSize, true,
sconfig.light, sconfig.emittance, sconfig.refraction, sconfig.reflection);
}
} }
PointType pos((float)x, (float)y, (float)z); if (!sconfig.fillInside) break;
grid.set(1,pos, true, colorVec, sconfig.voxelSize, true, sconfig.light, sconfig.emittance, sconfig.refraction, sconfig.reflection);
} // 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<int>& grid, defaults& config, const Camera& cam) { void livePreview(Octree<int>& grid, defaults& config, const Camera& cam) {
std::lock_guard<std::mutex> lock(PreviewMutex); std::lock_guard<std::mutex> lock(PreviewMutex);
updatePreview = true; 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); glGenTextures(1, &textu);
glBindTexture(GL_TEXTURE_2D, textu); glBindTexture(GL_TEXTURE_2D, textu);
@@ -217,10 +240,14 @@ int main() {
Octree<int> grid(minBound, maxBound, 16, 16); Octree<int> grid(minBound, maxBound, 16, 16);
bool gridInitialized = false; bool gridInitialized = false;
float ghalf = config.gridSizecube / 2.f; float ghalf = config.gridSizecube / 2.f;
Camera cam(PointType(ghalf, ghalf, ghalf), PointType(0,0,1), PointType(0,1,0), 80);
spheredefaults sphereConf; spheredefaults sphereConf;
ceilingdefaults ceilingConf; ceilingdefaults ceilingConf;
sphereConf.centerX = ghalf;
sphereConf.centerY = ghalf;
sphereConf.centerZ = ghalf;
bool autoRotate = false; bool autoRotate = false;
bool autoRotateView = false; bool autoRotateView = false;
float rotationSpeedX = 0.1f; float rotationSpeedX = 0.1f;
@@ -241,6 +268,7 @@ int main() {
float camvY = 0.f; float camvY = 0.f;
float camvZ = 0.f; float camvZ = 0.f;
float camspeed = 50; float camspeed = 50;
Camera cam(PointType(400, 400, 400), PointType(0,0,1), PointType(0,1,0), 80, camspeed);
// Keyboard state tracking // Keyboard state tracking
std::map<int, bool> keyStates; std::map<int, bool> keyStates;
@@ -254,6 +282,9 @@ int main() {
deltaTime = currentTime - lastFrameTime; deltaTime = currentTime - lastFrameTime;
lastFrameTime = currentTime; lastFrameTime = currentTime;
if (autoRotate) autoRotationTime += deltaTime;
if (autoRotateView) autoRotationAngle += deltaTime;
glfwPollEvents(); glfwPollEvents();
for (int i = GLFW_KEY_SPACE; i <= GLFW_KEY_LAST; i++) { for (int i = GLFW_KEY_SPACE; i <= GLFW_KEY_LAST; i++) {
@@ -315,7 +346,7 @@ int main() {
{ {
ImGui::Begin("Controls"); ImGui::Begin("Controls");
ImGui::Text("Sphere Parameters"); ImGui::Text("Planet");
float pos[3] = { sphereConf.centerX, sphereConf.centerY, sphereConf.centerZ }; float pos[3] = { sphereConf.centerX, sphereConf.centerY, sphereConf.centerZ };
if (ImGui::DragFloat3("Center (X,Y,Z)", pos, 1.0f, 0.0f, (float)config.gridSizecube)) { if (ImGui::DragFloat3("Center (X,Y,Z)", pos, 1.0f, 0.0f, (float)config.gridSizecube)) {
sphereConf.centerX = pos[0]; sphereConf.centerX = pos[0];
@@ -324,8 +355,15 @@ int main() {
} }
ImGui::DragFloat("Radius", &sphereConf.radius, 0.5f, 1.0f, 250.0f); 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::ColorEdit3("Color", sphereConf.color);
ImGui::DragFloat("Voxel Size", &sphereConf.voxelSize, 0.1f, 0.1f, 5.0f);
ImGui::Separator(); ImGui::Separator();
ImGui::Checkbox("Is Light", &sphereConf.light); ImGui::Checkbox("Is Light", &sphereConf.light);

View File

@@ -16,6 +16,8 @@ struct Camera {
float movementSpeed; float movementSpeed;
float rotationSpeed; 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, Camera(const Vector3f& pos, const Vector3f& viewdir, const Vector3f& up, float fov = 80,
float moveSpeed = 1.0f, float rotSpeed = 0.5f) float moveSpeed = 1.0f, float rotSpeed = 0.5f)
: origin(pos), direction(viewdir.normalized()), up(up.normalized()), fov(fov), movementSpeed(moveSpeed), rotationSpeed(rotSpeed) {} : origin(pos), direction(viewdir.normalized()), up(up.normalized()), fov(fov), movementSpeed(moveSpeed), rotationSpeed(rotSpeed) {}

View File

@@ -21,7 +21,6 @@
#endif #endif
constexpr int Dim = 3; constexpr int Dim = 3;
constexpr int maxBounces = 4;
template<typename T> template<typename T>
class Octree { class Octree {
@@ -384,7 +383,13 @@ private:
float x = randomValueNormalDistribution(state); float x = randomValueNormalDistribution(state);
float y = randomValueNormalDistribution(state); float y = randomValueNormalDistribution(state);
float z = 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 { float rgbToGrayscale(const Eigen::Vector3f& color) const {
@@ -435,7 +440,7 @@ public:
uint32_t magic; uint32_t magic;
readVal(in, magic); readVal(in, magic);
if (magic != 0x0C78E3) { if (magic != 0x79676733) {
std::cerr << "Invalid Octree file format" << std::endl; std::cerr << "Invalid Octree file format" << std::endl;
return false; return false;
} }
@@ -466,6 +471,8 @@ public:
if (!node || tMin > tMax) return; if (!node || tMin > tMax) return;
if (node->isLeaf) { if (node->isLeaf) {
for (const auto& pointData : node->points) { for (const auto& pointData : node->points) {
if (!pointData->active) continue;
PointType toPoint = pointData->position - origin; PointType toPoint = pointData->position - origin;
float projection = toPoint.dot(dir); float projection = toPoint.dot(dir);
if (projection >= 0 && projection <= maxDist) { if (projection >= 0 && projection <= maxDist) {
@@ -517,7 +524,7 @@ public:
return hits; 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 origin = cam.origin;
PointType dir = cam.direction.normalized(); PointType dir = cam.direction.normalized();
PointType up = cam.up.normalized(); PointType up = cam.up.normalized();
@@ -549,7 +556,7 @@ public:
if (bounces > maxBounces) return {0,0,0}; if (bounces > maxBounces) return {0,0,0};
auto hits = voxelTraverse(rayOrig, rayDir, rayLength, true); auto hits = voxelTraverse(rayOrig, rayDir, rayLength, true);
if (hits.empty() && bounces < 1) { if (hits.empty() && bounces == 0) {
return defaultColor; return defaultColor;
} else if (hits.empty()) { } else if (hits.empty()) {
return {0,0,0}; return {0,0,0};
@@ -626,21 +633,26 @@ public:
#pragma omp parallel for schedule(dynamic) collapse(2) #pragma omp parallel for schedule(dynamic) collapse(2)
for (int y = 0; y < height; ++y) { for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) { 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 px = (2.0f * (x + 0.5f) / width - 1.0f) * tanfovx;
float py = (1.0f - 2.0f * (y + 0.5f) / height) * tanfovy; float py = (1.0f - 2.0f * (y + 0.5f) / height) * tanfovy;
PointType rayDir = dir + (right * px) + (up * py); PointType rayDir = dir + (right * px) + (up * py);
rayDir.normalize(); rayDir.normalize();
int pidx = (y * width + x); Eigen::Vector3f accumulatedColor(0.0f, 0.0f, 0.0f);
uint32_t seed = pidx * 1973 + 9277;
int idx = pidx * channels;
Eigen::Vector3f color = traceRay(origin, rayDir, 0, seed); for(int s = 0; s < samplesPerPixel; ++s) {
accumulatedColor += traceRay(origin, rayDir, 0, seed);
}
Eigen::Vector3f color = accumulatedColor / static_cast<float>(samplesPerPixel);
color = color.cwiseMax(0.0f).cwiseMin(1.0f); color = color.cwiseMax(0.0f).cwiseMin(1.0f);
switch(colorformat) { switch(colorformat) {
case frame::colormap::B: case frame::colormap::B:
colorBuffer[idx ] = static_cast<uint8_t>(rgbToGrayscale(color) * 255.0f); colorBuffer[idx ] = static_cast<uint8_t>(rgbToGrayscale(color) * 255.0f);
@@ -667,7 +679,6 @@ public:
colorBuffer[idx + 2] = static_cast<uint8_t>(color[0] * 255.0f); colorBuffer[idx + 2] = static_cast<uint8_t>(color[0] * 255.0f);
colorBuffer[idx + 3] = 255; colorBuffer[idx + 3] = 255;
break; break;
} }
} }
} }