From d9aff085a8359dc716ae9727a9918bbd157bee24 Mon Sep 17 00:00:00 2001 From: Yggdrasil75 Date: Tue, 6 Jan 2026 14:49:09 -0500 Subject: [PATCH] pushing this. --- .gitignore | 5 +- tests/g3test2.cpp | 16 ++- util/grid/grid3.hpp | 316 ++++++++++++++++++++++++++++++-------------- 3 files changed, 228 insertions(+), 109 deletions(-) diff --git a/.gitignore b/.gitignore index c889aa1..1f2d0da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ /output/ /bin/ /web/output/ -imgui.ini \ No newline at end of file +imgui.ini +#prototyping in python below +*.py +/venv/ diff --git a/tests/g3test2.cpp b/tests/g3test2.cpp index 97339b5..b562271 100644 --- a/tests/g3test2.cpp +++ b/tests/g3test2.cpp @@ -43,10 +43,10 @@ void generateNoiseGrid(VoxelGrid& grid, PNoise2& noise) { // Create grayscale color based on noise value uint8_t grayValue = static_cast(noiseVal * 255); - Vec3ui8 color(grayValue, grayValue, grayValue); + Vec3ui8 color(grayValue, grayValue, 0); #pragma omp critical if (active > threshold) { - grid.set(x, y, z, active, color); + grid.set(x, y, z, true, color); } } } @@ -66,16 +66,18 @@ bool renderView(const std::string& filename, VoxelGrid& grid, const Vec3f& posit size_t height = RENDER_HEIGHT; // Render the view + //frame output = grid.renderFrame(position, direction, up, 40, RENDER_WIDTH, RENDER_HEIGHT); grid.renderOut(renderBuffer, width, height, cam); // Save to BMP + //bool success = BMPWriter::saveBMP(filename, output); bool success = BMPWriter::saveBMP(filename, renderBuffer, width, height); - if (success) { - std::cout << "Saved: " << filename << std::endl; - } else { - std::cout << "Failed to save: " << filename << std::endl; - } + // if (success) { + // std::cout << "Saved: " << filename << std::endl; + // } else { + // std::cout << "Failed to save: " << filename << std::endl; + // } return success; } diff --git a/util/grid/grid3.hpp b/util/grid/grid3.hpp index 794f49f..5cc84e5 100644 --- a/util/grid/grid3.hpp +++ b/util/grid/grid3.hpp @@ -13,7 +13,8 @@ #include "../basicdefines.hpp" struct Voxel { - float active; + //float active; + bool active; //Vec3f position; Vec3ui8 color; }; @@ -27,7 +28,8 @@ struct Camera { class VoxelGrid { private: - size_t width, height, depth; + Vec3T gridSize; + //size_t width, height, depth; std::vector voxels; float radians(float rads) { return rads * (M_PI / 180); @@ -67,21 +69,30 @@ private: std::pair rayBoxIntersect(const Vec3f& origin, const Vec3f& direction) { Vec3f tBMin = Vec3f(0,0,0); - Vec3f tBMax = Vec3f(width, height, depth); - float tmin = 0; + Vec3f tBMax = gridSize.toFloat(); + float tmin = -INF; float tmax = INF; Vec3f invDir = direction.safeInverse(); + bool allParallel = true; for (int i = 0; i < 3; ++i) { if (abs(direction[i]) < EPSILON) { - if (origin[i] < tBMin[i] || origin[i] > tBMax[i]) return std::make_pair(0.0f, 0.0f); - float t1 = tBMin[i] - origin[i] * invDir[i]; - float t2 = tBMax[i] - origin[i] * invDir[i]; - if (t1 > t2) std::swap(t1, t2); - if (t1 > tmin) tmin = t1; - if (t2 < tmax) tmax = t2; - if (tmin > tmax) return std::make_pair(0,0); + if (!(origin[i] < tBMin[i] || origin[i] > tBMax[i])) continue; } + allParallel = false; + float t1 = (tBMin[i] - origin[i]) * invDir[i]; + float t2 = (tBMax[i] - origin[i]) * invDir[i]; + + if (t1 > t2) std::swap(t1, t2); + + if (t1 > tmin) tmin = t1; + if (t2 < tmax) tmax = t2; + + if (tmin > tmax) return std::make_pair(0.0f, 0.0f); } + if (allParallel) { + return std::make_pair(0.0f, 0.0f); + } + if (tmax < 0) return std::make_pair(0.0f, 0.0f); return std::make_pair(tmin, tmax); } @@ -106,53 +117,53 @@ private: } public: - VoxelGrid(size_t w, size_t h, size_t d) : width(w), height(h), depth(d) { + VoxelGrid(size_t w, size_t h, size_t d) : gridSize(w,h,d) { voxels.resize(w * h * d); } Voxel& get(size_t x, size_t y, size_t z) { - return voxels[z * width * height + y * width + x]; + return voxels[z * gridSize.x * gridSize.y + y * gridSize.x + x]; } const Voxel& get(size_t x, size_t y, size_t z) const { - return voxels[z * width * height + y * width + x]; + return voxels[z * gridSize.x * gridSize.y + y * gridSize.x + x]; } Voxel& get(const Vec3T& xyz) { - return voxels[xyz.z*width*height+xyz.y*width+xyz.x]; + return voxels[xyz.z * gridSize.x * gridSize.y + xyz.y * gridSize.x + xyz.x]; } void resize() { //TODO: proper resizing } - void set(size_t x, size_t y, size_t z, float active, Vec3ui8 color) { + void set(size_t x, size_t y, size_t z, bool active, Vec3ui8 color) { set(Vec3T(x,y,z), active, color); } - void set(Vec3T pos, float active, Vec3ui8 color) { + void set(Vec3T pos, bool active, Vec3ui8 color) { if (pos.x >= 0 || pos.y >= 0 || pos.z >= 0) { - if (!(pos.x < width)) { + if (!(pos.x < gridSize.x)) { //until resizing added: return; - width = pos.x; + gridSize.x = pos.x; resize(); } - else if (!(pos.y < height)) { + else if (!(pos.y < gridSize.y)) { //until resizing added: return; - height = pos.y; + gridSize.y = pos.y; resize(); } - else if (!(pos.z < depth)) { + else if (!(pos.z < gridSize.z)) { //until resizing added: return; - depth = pos.z; + gridSize.z = pos.z; resize(); } Voxel& v = get(pos); - v.active = std::clamp(active, 0.0f, 1.0f); + v.active = active; // std::clamp(active, 0.0f, 1.0f); v.color = color; } } @@ -163,7 +174,7 @@ public: template bool inGrid(Vec3 voxl) { - return (voxl >= 0 && voxl.x < width && voxl.y < height && voxl.z < depth); + return (voxl >= 0 && voxl.x < gridSize.x && voxl.y < gridSize.y && voxl.z < gridSize.z); } std::vector genPixelDirs(const Vec3f& pos, const Vec3f& dir, size_t imgWidth, size_t imgHeight, float fov) { @@ -208,78 +219,110 @@ public: return rayDirWorld.normalized(); } + bool castRay(const Vec3f& origin, const Vec3f& direction, float maxDist, Vec3f& hitColor) { + Vec3f dir = direction.normalized(); + Vec3T pos = origin.floorToT(); + Vec3i step = Vec3i(dir.x > 0 ? -1 : 1, dir.y > 0 ? -1 : 1, dir.z > 0 ? -1 : 1); + Vec3f tMax; + Vec3f tDelta; + if (abs(dir.x) > EPSILON) { + tMax.x = (static_cast(pos.x) + (step.x > 0 ? 1 : 0) - pos.x) / dir.x; + tDelta.x = step.x / dir.x; + } else { + tMax.x = INF; + tDelta.x = INF; + } + if (abs(dir.y) > EPSILON) { + tMax.y = (static_cast(pos.y) + (step.y > 0 ? 1 : 0) - pos.y) / dir.y; + tDelta.y = step.y / dir.y; + } else { + tMax.y = INF; + tDelta.y = INF; + } + if (abs(dir.z) > EPSILON) { + tMax.z = (static_cast(pos.z) + (step.z > 0 ? 1 : 0) - pos.z) / dir.z; + tDelta.z = step.z / dir.z; + } else { + tMax.z = INF; + tDelta.z = INF; + } + + auto intersect = rayBoxIntersect(origin, dir); + float tEntry = intersect.first; + float tExit = intersect.second; + if (tEntry <= 0 && tExit <= 0) return false; + if (tEntry > maxDist) return false; + + float dist = 0; + while (dist < maxDist) { + if (inGrid(pos)) { + Voxel cv = get(pos); + if (cv.active) { + Vec3f norm = Vec3f(0,0,0); + if (tMax.x <= tMax.y && tMax.x <= tMax.z) norm.x = -step.x; + else if (tMax.y <= tMax.x && tMax.y <= tMax.z) norm.y = -step.y; + else norm.z = -step.z; + hitColor = cv.color.toFloat() / 255; + return true; + } + } + if (tMax.x <= tMax.y && tMax.x <= tMax.z) { + pos.x += step.x; + dist += tDelta.x; + //dist = tMax.x; + tMax.x += tDelta.x; + } else if (tMax.y <= tMax.x && tMax.y <= tMax.z) { + pos.y += step.y; + //dist = tMax.y; + dist += tDelta.y; + tMax.y += tDelta.y; + } else { + pos.z += step.z; + //dist = tMax.z; + dist += tDelta.z; + tMax.z += tDelta.z; + } + } + return false; + } + bool rayCast(const Vec3f& origin, const Vec3f& direction, float maxDist, Vec3f& hitColor) { Vec3f dir = direction.normalized(); if (abs(dir.length()) < EPSILON) return false; - Vec3f invDir = dir.safeInverse(); - Vec3T currentVoxel = origin.floorToT(); - if (dir.x == 0 || dir.y == 0 || dir.z == 0) { return specialCases(origin, dir, maxDist, hitColor); } + float tStart; + Vec3f invDir = dir.safeInverse(); + Vec3T currentVoxel = origin.floorToT(); if (!inGrid(currentVoxel)) { std::pair re = rayBoxIntersect(origin, dir); float tEntry = re.first; float tExit = re.second; if (tEntry < EPSILON || tExit < EPSILON) return false; - float tStart = std::max(0.0f, tEntry); - if (tStart > maxDist) return false; - Vec3f gridOrig = origin + dir * tStart; - currentVoxel = gridOrig.floorToT(); + if (tEntry > maxDist) return false; + tStart = tEntry; } + Vec3f gridOrig = origin + dir * tStart; + currentVoxel = gridOrig.floorToT(); Vec3i8 step = Vec3i8(dir.x >= 0 ? 1 : -1, dir.y >= 0 ? 1 : -1, dir.z >= 0 ? 1 : -1); Vec3f tMax; + float tDist = tStart; for (int i = 0; i < 3; i++) { if (step[i] > 0) { - tMax[i] = ((currentVoxel[i] + 1) - origin[i]) * invDir[i]; + tMax[i] = ((currentVoxel[i] + 1) - gridOrig[i]) * invDir[i]; } else { - tMax[i] = (currentVoxel[i] - origin[i]) * invDir[i]; + tMax[i] = (currentVoxel[i] - gridOrig[i]) * invDir[i]; } } Vec3f tDelta = invDir.abs(); - // Vec3f dir = direction.normalized(); - // if (abs(dir.length()) < EPSILON) return false; - - // Vec3f invDir = dir.safeInverse(); - // Vec3T currentVoxel = origin.floorToT(); - - // if (dir.x == 0 || dir.y == 0 || dir.z == 0) { - // return specialCases(origin, dir, maxDist, hitColor); - // } - - // //if (!inGrid(currentVoxel)) { - // std::pair re = rayBoxIntersect(origin, dir); - // float tEntry = re.first; - // float tExit = re.second; - // float tStart = std::max(0.0f, tEntry); - // if (tEntry < EPSILON || tExit < EPSILON || tStart > maxDist) return false; - // Vec3f gridOrig = origin + dir * tStart; - // currentVoxel = gridOrig.floorToT(); - // //} - - // Vec3i8 step = Vec3i8(direction.x >= 0 ? 1 : -1, direction.y >= 0 ? 1 : -1, direction.z >= 0 ? 1 : -1); - // Vec3f tMax; - // Vec3f tDelta = invDir.abs(); - // for (int i = 0; i < 3; i++) { - // //if (step[i] != 0) { - // if (step[i] > 0) { - // tMax[i] = ((currentVoxel[i] + 1) - origin[i]) * invDir[i]; - // } else { - // tMax[i] = (currentVoxel[i] - origin[i]) * invDir[i]; - // } - // //tDelta[i] = fabs(1.0f / dir[i]); - // //} else { - // //tMax[i] = INF; - // //tDelta[i] = INF; - // //} - // } float aalpha = 0; - while (inGrid(currentVoxel) && aalpha < 1) { + while (inGrid(currentVoxel) && aalpha < 1 && tDist <= maxDist) { Voxel cv = get(currentVoxel); if (cv.active > EPSILON) { float alpha = cv.active * (1.0f - aalpha); @@ -289,15 +332,17 @@ public: } if (tMax.x < tMax.y && tMax.x < tMax.z) { + tDist = tDist + tDelta.x; if (tMax.x > maxDist) break; currentVoxel.x += step.x; tMax.x += tDelta.x; - } else if (tMax.y < tMax.z) - { + } else if (tMax.y < tMax.z) { + tDist = tDist + tDelta.y; currentVoxel.y += step.y; tMax.y += tDelta.y; } else { + tDist = tDist + tDelta.z; currentVoxel.z += step.z; tMax.z += tDelta.z; } @@ -309,48 +354,117 @@ public: } size_t getWidth() const { - return width; + return gridSize.x; } size_t getHeight() const { - return height; + return gridSize.y; } size_t getDepth() const { - return depth; + return gridSize.z; + } + + frame renderFrame(const Vec3f& CamPos, const Vec3f& lookAt, const Vec3f& up, float fov, size_t outW, size_t outH) { + TIME_FUNCTION; + Vec3f forward = (lookAt - CamPos).normalized(); + Vec3f right = forward.cross(up).normalized(); + Vec3f upCor = right.cross(forward).normalized(); + float aspect = outW / outH; + float fovRad = radians(fov); + float viewH = 2 * tan(fovRad / 2); + float viewW = viewH * aspect; + float maxDist = gridSize.lengthSquared() / 2; + frame outFrame = frame(outH,outW, frame::colormap::RGB); + std::vector colorBuffer(outW * outH * 3); + #pragma omp parallel for + for (size_t y = 0; y < outH; y++) { + float v = (y + 0.5) / outH - 0.5; + for (size_t x = 0; x < outW; x++) { + float u = (x + 0.5) / outW - 0.5; + Vec3f rayDir = (forward + right * (u + viewW) + upCor * (v * viewH)).normalized(); + Vec3f hitColor = Vec3f(0,0,0); + bool hit = castRay(CamPos, rayDir, maxDist, hitColor); + size_t idx = y*outW+x; + if (!hit) { + hitColor = Vec3f(0.1,0.1,1.0f); + } else { + std::cout << "hit"; + } + colorBuffer[idx + 0] = static_cast(hitColor.x * 255); + colorBuffer[idx + 1] = static_cast(hitColor.y * 255); + colorBuffer[idx + 2] = static_cast(hitColor.z * 255); + } + } + std::cout << std::endl; + outFrame.setData(colorBuffer); + return outFrame; } void renderOut(std::vector& output, size_t& outwidth, size_t& outheight, const Camera& cam) { TIME_FUNCTION; - output.resize(outwidth * outheight * 3); - Vec3f backgroundColor(0.1f, 0.1f, 1.0f); - float maxDistance = std::sqrt(width*width + height*height + depth*depth) * 2.0f; - // std::vector dirs = genPixelDirs(cam.posfor.origin, cam.posfor.direction, outwidth, outheight, cam.fov); - - for (size_t y = 0; y < outheight; y++) { - float yout = y * outwidth; + Vec3f forward = (cam.posfor.direction - cam.posfor.origin).normalized(); + Vec3f right = forward.cross(cam.up).normalized(); + Vec3f upCor = right.cross(forward).normalized(); + float aspect = outwidth / outheight; + float fovRad = radians(cam.fov); + float viewH = 2 * tan(fovRad / 2); + float viewW = viewH * aspect; + float maxDist = gridSize.lengthSquared() / 2; + //frame outFrame = frame(outH,outW, frame::colormap::RGB); + std::vector colorBuffer(outwidth * outheight * 3); + #pragma omp parallel for + for (size_t y = 0; y < outheight; y++) { + float v = (y + 0.5) / outheight - 0.5; for (size_t x = 0; x < outwidth; x++) { - // Vec3f rayDir = dirs[y*outwidth + x]; - // Vec3f hitColor = Vec3f(0,0,0); - Vec3f rayDir = perPixelRayDir(x, y, outwidth, outheight, cam); - Ray3f ray(cam.posfor.origin, rayDir); - Vec3f hitPos; - Vec3f hitNorm; - Vec3f hitColor; - bool hit = rayCast(cam.posfor.origin, rayDir, maxDistance, hitColor); - - Vec3f finalColor; + float u = (x + 0.5) / outwidth - 0.5; + Vec3f rayDir = (forward + right * (u + viewW) + upCor * (v * viewH)).normalized(); + Vec3f hitColor = Vec3f(0,0,0); + bool hit = castRay(cam.posfor.origin, rayDir, maxDist, hitColor); + size_t idx = y*outwidth+x; if (!hit) { - finalColor = backgroundColor; + hitColor = Vec3f(0.1,0.1,1.0f); } else { - finalColor = hitColor; + std::cout << "hit"; } - - finalColor = finalColor.clamp(0, 1); - size_t pixelIndex = (yout + x) * 3; - output[pixelIndex + 0] = static_cast(finalColor.x * 255); - output[pixelIndex + 1] = static_cast(finalColor.y * 255); - output[pixelIndex + 2] = static_cast(finalColor.z * 255); + colorBuffer[idx + 0] = static_cast(hitColor.x * 255); + colorBuffer[idx + 1] = static_cast(hitColor.y * 255); + colorBuffer[idx + 2] = static_cast(hitColor.z * 255); } } + std::cout << std::endl; + output = colorBuffer; + // TIME_FUNCTION; + // output.resize(outwidth * outheight * 3); + // Vec3f backgroundColor(0.1f, 0.1f, 1.0f); + // float maxDistance = sqrt(gridSize.lengthSquared()) * 2; + // //float maxDistance = std::sqrt(width*width + height*height + depth*depth) * 2.0f; + // // std::vector dirs = genPixelDirs(cam.posfor.origin, cam.posfor.direction, outwidth, outheight, cam.fov); + + // for (size_t y = 0; y < outheight; y++) { + // float yout = y * outwidth; + // for (size_t x = 0; x < outwidth; x++) { + // // Vec3f rayDir = dirs[y*outwidth + x]; + // // Vec3f hitColor = Vec3f(0,0,0); + // Vec3f rayDir = perPixelRayDir(x, y, outwidth, outheight, cam); + // Ray3f ray(cam.posfor.origin, rayDir); + // Vec3f hitPos; + // Vec3f hitNorm; + // Vec3f hitColor; + // bool hit = castRay(cam.posfor.origin, rayDir, maxDistance, hitColor); + + // Vec3f finalColor; + // if (!hit) { + // finalColor = backgroundColor; + // } else { + // finalColor = hitColor; + // } + + // finalColor = finalColor.clamp(0, 1); + // size_t pixelIndex = (yout + x) * 3; + // output[pixelIndex + 0] = static_cast(finalColor.x * 255); + // output[pixelIndex + 1] = static_cast(finalColor.y * 255); + // output[pixelIndex + 2] = static_cast(finalColor.z * 255); + // } + // } } };