pushing this.

This commit is contained in:
Yggdrasil75
2026-01-06 14:49:09 -05:00
parent b74ba3cfdc
commit d9aff085a8
3 changed files with 228 additions and 109 deletions

3
.gitignore vendored
View File

@@ -2,3 +2,6 @@
/bin/ /bin/
/web/output/ /web/output/
imgui.ini imgui.ini
#prototyping in python below
*.py
/venv/

View File

@@ -43,10 +43,10 @@ void generateNoiseGrid(VoxelGrid& grid, PNoise2& noise) {
// Create grayscale color based on noise value // Create grayscale color based on noise value
uint8_t grayValue = static_cast<uint8_t>(noiseVal * 255); uint8_t grayValue = static_cast<uint8_t>(noiseVal * 255);
Vec3ui8 color(grayValue, grayValue, grayValue); Vec3ui8 color(grayValue, grayValue, 0);
#pragma omp critical #pragma omp critical
if (active > threshold) { 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; size_t height = RENDER_HEIGHT;
// Render the view // Render the view
//frame output = grid.renderFrame(position, direction, up, 40, RENDER_WIDTH, RENDER_HEIGHT);
grid.renderOut(renderBuffer, width, height, cam); grid.renderOut(renderBuffer, width, height, cam);
// Save to BMP // Save to BMP
//bool success = BMPWriter::saveBMP(filename, output);
bool success = BMPWriter::saveBMP(filename, renderBuffer, width, height); bool success = BMPWriter::saveBMP(filename, renderBuffer, width, height);
if (success) { // if (success) {
std::cout << "Saved: " << filename << std::endl; // std::cout << "Saved: " << filename << std::endl;
} else { // } else {
std::cout << "Failed to save: " << filename << std::endl; // std::cout << "Failed to save: " << filename << std::endl;
} // }
return success; return success;
} }

View File

@@ -13,7 +13,8 @@
#include "../basicdefines.hpp" #include "../basicdefines.hpp"
struct Voxel { struct Voxel {
float active; //float active;
bool active;
//Vec3f position; //Vec3f position;
Vec3ui8 color; Vec3ui8 color;
}; };
@@ -27,7 +28,8 @@ struct Camera {
class VoxelGrid { class VoxelGrid {
private: private:
size_t width, height, depth; Vec3T gridSize;
//size_t width, height, depth;
std::vector<Voxel> voxels; std::vector<Voxel> voxels;
float radians(float rads) { float radians(float rads) {
return rads * (M_PI / 180); return rads * (M_PI / 180);
@@ -67,21 +69,30 @@ private:
std::pair<float,float> rayBoxIntersect(const Vec3f& origin, const Vec3f& direction) { std::pair<float,float> rayBoxIntersect(const Vec3f& origin, const Vec3f& direction) {
Vec3f tBMin = Vec3f(0,0,0); Vec3f tBMin = Vec3f(0,0,0);
Vec3f tBMax = Vec3f(width, height, depth); Vec3f tBMax = gridSize.toFloat();
float tmin = 0; float tmin = -INF;
float tmax = INF; float tmax = INF;
Vec3f invDir = direction.safeInverse(); Vec3f invDir = direction.safeInverse();
bool allParallel = true;
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
if (abs(direction[i]) < EPSILON) { if (abs(direction[i]) < EPSILON) {
if (origin[i] < tBMin[i] || origin[i] > tBMax[i]) return std::make_pair(0.0f, 0.0f); if (!(origin[i] < tBMin[i] || origin[i] > tBMax[i])) continue;
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);
} }
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); return std::make_pair(tmin, tmax);
} }
@@ -106,53 +117,53 @@ private:
} }
public: 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); voxels.resize(w * h * d);
} }
Voxel& get(size_t x, size_t y, size_t z) { 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 { 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) { 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() { void resize() {
//TODO: proper resizing //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); 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 >= 0 || pos.y >= 0 || pos.z >= 0) {
if (!(pos.x < width)) { if (!(pos.x < gridSize.x)) {
//until resizing added: //until resizing added:
return; return;
width = pos.x; gridSize.x = pos.x;
resize(); resize();
} }
else if (!(pos.y < height)) { else if (!(pos.y < gridSize.y)) {
//until resizing added: //until resizing added:
return; return;
height = pos.y; gridSize.y = pos.y;
resize(); resize();
} }
else if (!(pos.z < depth)) { else if (!(pos.z < gridSize.z)) {
//until resizing added: //until resizing added:
return; return;
depth = pos.z; gridSize.z = pos.z;
resize(); resize();
} }
Voxel& v = get(pos); 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; v.color = color;
} }
} }
@@ -163,7 +174,7 @@ public:
template<typename T> template<typename T>
bool inGrid(Vec3<T> voxl) { bool inGrid(Vec3<T> 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<Vec3f> genPixelDirs(const Vec3f& pos, const Vec3f& dir, size_t imgWidth, size_t imgHeight, float fov) { std::vector<Vec3f> genPixelDirs(const Vec3f& pos, const Vec3f& dir, size_t imgWidth, size_t imgHeight, float fov) {
@@ -208,78 +219,110 @@ public:
return rayDirWorld.normalized(); 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<size_t>(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<size_t>(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<size_t>(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) { bool rayCast(const Vec3f& origin, const Vec3f& direction, float maxDist, Vec3f& hitColor) {
Vec3f dir = direction.normalized(); Vec3f dir = direction.normalized();
if (abs(dir.length()) < EPSILON) return false; 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) { if (dir.x == 0 || dir.y == 0 || dir.z == 0) {
return specialCases(origin, dir, maxDist, hitColor); return specialCases(origin, dir, maxDist, hitColor);
} }
float tStart;
Vec3f invDir = dir.safeInverse();
Vec3T currentVoxel = origin.floorToT();
if (!inGrid(currentVoxel)) { if (!inGrid(currentVoxel)) {
std::pair<float,float> re = rayBoxIntersect(origin, dir); std::pair<float,float> re = rayBoxIntersect(origin, dir);
float tEntry = re.first; float tEntry = re.first;
float tExit = re.second; float tExit = re.second;
if (tEntry < EPSILON || tExit < EPSILON) return false; if (tEntry < EPSILON || tExit < EPSILON) return false;
float tStart = std::max(0.0f, tEntry); if (tEntry > maxDist) return false;
if (tStart > maxDist) return false; tStart = tEntry;
Vec3f gridOrig = origin + dir * tStart;
currentVoxel = gridOrig.floorToT();
} }
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); Vec3i8 step = Vec3i8(dir.x >= 0 ? 1 : -1, dir.y >= 0 ? 1 : -1, dir.z >= 0 ? 1 : -1);
Vec3f tMax; Vec3f tMax;
float tDist = tStart;
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (step[i] > 0) { if (step[i] > 0) {
tMax[i] = ((currentVoxel[i] + 1) - origin[i]) * invDir[i]; tMax[i] = ((currentVoxel[i] + 1) - gridOrig[i]) * invDir[i];
} else { } else {
tMax[i] = (currentVoxel[i] - origin[i]) * invDir[i]; tMax[i] = (currentVoxel[i] - gridOrig[i]) * invDir[i];
} }
} }
Vec3f tDelta = invDir.abs(); 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<float,float> 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; float aalpha = 0;
while (inGrid(currentVoxel) && aalpha < 1) { while (inGrid(currentVoxel) && aalpha < 1 && tDist <= maxDist) {
Voxel cv = get(currentVoxel); Voxel cv = get(currentVoxel);
if (cv.active > EPSILON) { if (cv.active > EPSILON) {
float alpha = cv.active * (1.0f - aalpha); float alpha = cv.active * (1.0f - aalpha);
@@ -289,15 +332,17 @@ public:
} }
if (tMax.x < tMax.y && tMax.x < tMax.z) { if (tMax.x < tMax.y && tMax.x < tMax.z) {
tDist = tDist + tDelta.x;
if (tMax.x > maxDist) break; if (tMax.x > maxDist) break;
currentVoxel.x += step.x; currentVoxel.x += step.x;
tMax.x += tDelta.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; currentVoxel.y += step.y;
tMax.y += tDelta.y; tMax.y += tDelta.y;
} }
else { else {
tDist = tDist + tDelta.z;
currentVoxel.z += step.z; currentVoxel.z += step.z;
tMax.z += tDelta.z; tMax.z += tDelta.z;
} }
@@ -309,48 +354,117 @@ public:
} }
size_t getWidth() const { size_t getWidth() const {
return width; return gridSize.x;
} }
size_t getHeight() const { size_t getHeight() const {
return height; return gridSize.y;
} }
size_t getDepth() const { 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<uint8_t> 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<uint8_t>(hitColor.x * 255);
colorBuffer[idx + 1] = static_cast<uint8_t>(hitColor.y * 255);
colorBuffer[idx + 2] = static_cast<uint8_t>(hitColor.z * 255);
}
}
std::cout << std::endl;
outFrame.setData(colorBuffer);
return outFrame;
} }
void renderOut(std::vector<uint8_t>& output, size_t& outwidth, size_t& outheight, const Camera& cam) { void renderOut(std::vector<uint8_t>& output, size_t& outwidth, size_t& outheight, const Camera& cam) {
TIME_FUNCTION; TIME_FUNCTION;
output.resize(outwidth * outheight * 3); Vec3f forward = (cam.posfor.direction - cam.posfor.origin).normalized();
Vec3f backgroundColor(0.1f, 0.1f, 1.0f); Vec3f right = forward.cross(cam.up).normalized();
float maxDistance = std::sqrt(width*width + height*height + depth*depth) * 2.0f; Vec3f upCor = right.cross(forward).normalized();
// std::vector<Vec3f> dirs = genPixelDirs(cam.posfor.origin, cam.posfor.direction, outwidth, outheight, cam.fov); 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<uint8_t> colorBuffer(outwidth * outheight * 3);
#pragma omp parallel for
for (size_t y = 0; y < outheight; y++) { for (size_t y = 0; y < outheight; y++) {
float yout = y * outwidth; float v = (y + 0.5) / outheight - 0.5;
for (size_t x = 0; x < outwidth; x++) { for (size_t x = 0; x < outwidth; x++) {
// Vec3f rayDir = dirs[y*outwidth + x]; float u = (x + 0.5) / outwidth - 0.5;
// Vec3f hitColor = Vec3f(0,0,0); Vec3f rayDir = (forward + right * (u + viewW) + upCor * (v * viewH)).normalized();
Vec3f rayDir = perPixelRayDir(x, y, outwidth, outheight, cam); Vec3f hitColor = Vec3f(0,0,0);
Ray3f ray(cam.posfor.origin, rayDir); bool hit = castRay(cam.posfor.origin, rayDir, maxDist, hitColor);
Vec3f hitPos; size_t idx = y*outwidth+x;
Vec3f hitNorm;
Vec3f hitColor;
bool hit = rayCast(cam.posfor.origin, rayDir, maxDistance, hitColor);
Vec3f finalColor;
if (!hit) { if (!hit) {
finalColor = backgroundColor; hitColor = Vec3f(0.1,0.1,1.0f);
} else { } else {
finalColor = hitColor; std::cout << "hit";
} }
colorBuffer[idx + 0] = static_cast<uint8_t>(hitColor.x * 255);
finalColor = finalColor.clamp(0, 1); colorBuffer[idx + 1] = static_cast<uint8_t>(hitColor.y * 255);
size_t pixelIndex = (yout + x) * 3; colorBuffer[idx + 2] = static_cast<uint8_t>(hitColor.z * 255);
output[pixelIndex + 0] = static_cast<uint8_t>(finalColor.x * 255);
output[pixelIndex + 1] = static_cast<uint8_t>(finalColor.y * 255);
output[pixelIndex + 2] = static_cast<uint8_t>(finalColor.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<Vec3f> 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<uint8_t>(finalColor.x * 255);
// output[pixelIndex + 1] = static_cast<uint8_t>(finalColor.y * 255);
// output[pixelIndex + 2] = static_cast<uint8_t>(finalColor.z * 255);
// }
// }
} }
}; };