diff --git a/tests/g3test2.cpp b/tests/g3test2.cpp index debe1ca..ff6abdc 100644 --- a/tests/g3test2.cpp +++ b/tests/g3test2.cpp @@ -23,9 +23,9 @@ struct defaults { int outWidth = 512; int outHeight = 512; - int gridWidth = 512; - int gridHeight = 512; - int gridDepth = 512; + int gridWidth = 256; + int gridHeight = 256; + int gridDepth = 256; float fps = 30.0f; PNoise2 noise = PNoise2(42); }; diff --git a/util/grid/grid3.hpp b/util/grid/grid3.hpp index 054863f..09cbf64 100644 --- a/util/grid/grid3.hpp +++ b/util/grid/grid3.hpp @@ -53,10 +53,10 @@ Mat4f perspective(float fovy, float aspect, float zNear, float zfar) { } struct Voxel { - float weight; - bool active; - float alpha; - Vec3ui8 color; + float weight = 1.0; + bool active = false; + float alpha = 0.0; + Vec3ui8 color = Vec3ui8(0,0,0); Voxel() = default; Voxel(float weight, bool active, float alpha, Vec3ui8 color) : weight(weight), active(active), alpha(alpha), color(color) {} // TODO: add curving and similar for water and glass and so on. @@ -155,13 +155,12 @@ struct Chunk { if (children.empty()) { int index = getVoxelIndex(pos); - if (index >= 0 && index < static_cast(voxels.size())) { + //if (index >= 0 && index < static_cast(voxels.size())) { voxels[index] = newVox; dirty = true; return true; - - } - return false; + // } + // return false; } for (Chunk& child : children) { @@ -223,7 +222,7 @@ struct Chunk { return Voxel(); } - const Voxel get(const Vec3i& pos, int maxDepth = 0) const { + const Voxel& get(const Vec3i& pos, int maxDepth = 0) const { if (!inChunk(pos)) { return Voxel(); } @@ -251,12 +250,11 @@ struct Chunk { int getVoxelIndex(Vec3i pos) const { Vec3i localPos = pos - minCorner; - return localPos.z * chunkSize.x * chunkSize.y + - localPos.y * chunkSize.x + - localPos.x; + return localPos.z * chunkSize.x * chunkSize.y + localPos.y * chunkSize.x + localPos.x; } void updateAverages() { + TIME_FUNCTION; if (voxels.empty()) { weight = 0.0f; alpha = 0.0f; @@ -303,6 +301,7 @@ struct Chunk { } void updateAveragesRecursive() { + TIME_FUNCTION; if (children.empty()) { updateAverages(); } else { @@ -353,6 +352,7 @@ struct Chunk { } void subdivide(int numChildrenPerAxis = 2) { + TIME_FUNCTION; if (!children.empty()) return; // Already subdivided Vec3i childSize = (maxCorner - minCorner) / numChildrenPerAxis; @@ -387,13 +387,10 @@ struct Chunk { } } } - - // Clear parent voxels after subdivision to save memory - voxels.clear(); - voxels.shrink_to_fit(); } void merge() { + TIME_FUNCTION; if (children.empty()) return; // Calculate total size from children @@ -441,6 +438,55 @@ private: return rads * (M_PI / 180); } + void createChunksFromVoxels() { + TIME_FUNCTION; + chunks.clear(); + + // Create chunks based on CHUNK_THRESHOLD + int chunksX = std::max(1, (gridSize.x + CHUNK_THRESHOLD - 1) / CHUNK_THRESHOLD); + int chunksY = std::max(1, (gridSize.y + CHUNK_THRESHOLD - 1) / CHUNK_THRESHOLD); + int chunksZ = std::max(1, (gridSize.z + CHUNK_THRESHOLD - 1) / CHUNK_THRESHOLD); + + Vec3i chunkSize = Vec3i( + (gridSize.x + chunksX - 1) / chunksX, + (gridSize.y + chunksY - 1) / chunksY, + (gridSize.z + chunksZ - 1) / chunksZ + ); + + for (int z = 0; z < chunksZ; z++) { + for (int y = 0; y < chunksY; y++) { + for (int x = 0; x < chunksX; x++) { + Vec3i minCorner = Vec3i(x * chunkSize.x, y * chunkSize.y, z * chunkSize.z); + Vec3i maxCorner = Vec3i( + std::min(minCorner.x + chunkSize.x, gridSize.x), + std::min(minCorner.y + chunkSize.y, gridSize.y), + std::min(minCorner.z + chunkSize.z, gridSize.z) + ); + + Chunk chunk(minCorner, maxCorner); + + // Copy voxel data to chunk + for (int cz = minCorner.z; cz < maxCorner.z; cz++) { + for (int cy = minCorner.y; cy < maxCorner.y; cy++) { + for (int cx = minCorner.x; cx < maxCorner.x; cx++) { + Vec3i pos(cx, cy, cz); + int voxelIndex = cz * gridSize.x * gridSize.y + cy * gridSize.x + cx; + int chunkIndex = chunk.getVoxelIndex(pos); + + if (voxelIndex >= 0 && voxelIndex < static_cast(voxels.size()) && + chunkIndex >= 0 && chunkIndex < static_cast(chunk.voxels.size())) { + chunk.voxels[chunkIndex] = voxels[voxelIndex]; + } + } + } + } + + chunks.push_back(chunk); + } + } + } + } + public: double binSize = 1; VoxelGrid() : gridSize(0,0,0) { @@ -449,6 +495,12 @@ public: VoxelGrid(int w, int h, int d) : gridSize(w,h,d) { voxels.resize(w * h * d); + + // // Enable chunks if any dimension exceeds CHUNK_THRESHOLD + // if (w > CHUNK_THRESHOLD || h > CHUNK_THRESHOLD || d > CHUNK_THRESHOLD) { + // useChunks = true; + // createChunksFromVoxels(); + // } } bool serializeToFile(const std::string& filename); @@ -456,26 +508,46 @@ public: static std::unique_ptr deserializeFromFile(const std::string& filename); Voxel& get(int x, int y, int z) { + if (useChunks) { + for (Chunk& chunk : chunks) { + if (chunk.inChunk(Vec3i(x, y, z))) { + Voxel* voxelPtr = chunk.getPtr(Vec3i(x, y, z)); + if (voxelPtr) { + return *voxelPtr; + } + } + } + } return voxels[z * gridSize.x * gridSize.y + y * gridSize.x + x]; } const Voxel& get(int x, int y, int z) const { + if (useChunks) { + for (const Chunk& chunk : chunks) { + if (chunk.inChunk(Vec3i(x, y, z))) { + Voxel voxel = chunk.get(Vec3i(x, y, z)); + return voxel; + } + } + } return voxels[z * gridSize.x * gridSize.y + y * gridSize.x + x]; } Voxel& get(const Vec3i& xyz) { - return voxels[xyz.z * gridSize.x * gridSize.y + xyz.y * gridSize.x + xyz.x]; + return get(xyz.x, xyz.y, xyz.z); } const Voxel& get(const Vec3i& xyz) const { - return voxels[xyz.z * gridSize.x * gridSize.y + xyz.y * gridSize.x + xyz.x]; + return get(xyz.x, xyz.y, xyz.z); } void resize(int newW, int newH, int newD) { + TIME_FUNCTION; std::vector newVoxels(newW * newH * newD); int copyW = std::min(static_cast(gridSize.x), newW); int copyH = std::min(static_cast(gridSize.y), newH); int copyD = std::min(static_cast(gridSize.z), newD); + for (int z = 0; z < copyD; ++z) { for (int y = 0; y < copyH; ++y) { int oldRowStart = z * gridSize.x * gridSize.y + y * gridSize.x; @@ -487,8 +559,18 @@ public: ); } } + voxels = std::move(newVoxels); gridSize = Vec3i(newW, newH, newD); + + // Check if we need to enable chunks + if (newW > CHUNK_THRESHOLD || newH > CHUNK_THRESHOLD || newD > CHUNK_THRESHOLD) { + useChunks = true; + createChunksFromVoxels(); + } else { + useChunks = false; + chunks.clear(); + } } void resize(Vec3i newsize) { @@ -512,8 +594,21 @@ public: } Voxel& v = get(pos); - v.active = active; // std::clamp(active, 0.0f, 1.0f); + v.active = active; v.color = color; + + // // Also update in chunks if using chunks + // if (useChunks) { + // for (Chunk& chunk : chunks) { + // if (chunk.inChunk(pos)) { + // Voxel newVoxel; + // newVoxel.active = active; + // newVoxel.color = color; + // chunk.set(pos, newVoxel); + // break; + // } + // } + // } } } @@ -560,8 +655,10 @@ public: } while (lv != cv && inGrid(cv) && visitedVoxel.size() < 10) { - if (get(cv).active) { - visitedVoxel.push_back(cv); + const Voxel& cvv = get(cv); + + if (cvv.active) { + visitedVoxel.push_back(cv); } if (tMax.x < tMax.y) { if (tMax.x < tMax.z) { @@ -606,7 +703,7 @@ public: float maxDist = std::sqrt(gridSize.lengthSquared()) * binSize; frame outFrame(resolution.x, resolution.y, frame::colormap::RGB); std::vector colorBuffer(resolution.x * resolution.y * 3); - #pragma omp parallel for + //#pragma omp parallel for for (int y = 0; y < resolution.x; y++) { float v = (static_cast(y) / static_cast(resolution.x - 1)) - 0.5f; for (int x = 0; x < resolution.y; x++) { @@ -616,7 +713,9 @@ public: Vec3f rayEnd = cam.posfor.origin + rayDirWorld * maxDist; Vec3d rayStartGrid = cam.posfor.origin.toDouble() / binSize; Vec3d rayEndGrid = rayEnd.toDouble() / binSize; + std::cout << "traversing"; voxelTraverse(rayStartGrid, rayEndGrid, hitVoxels); + std::cout << "traversed"; Vec3ui8 hitColor(10, 10, 255); for (const Vec3i& voxelPos : hitVoxels) { if (inGrid(voxelPos)) { @@ -628,6 +727,7 @@ public: } } } + std::cout << "hit done" << std::endl; hitVoxels.clear(); hitVoxels.shrink_to_fit(); // Set pixel color in buffer @@ -808,8 +908,7 @@ public: return outframes; } - -}; + }; //#include "g3_serialization.hpp" needed to be usable #endif