From 02115dcfc0ffad5ceb1a04631ce90128298c423e Mon Sep 17 00:00:00 2001 From: Yggdrasil75 Date: Tue, 30 Dec 2025 15:00:58 -0500 Subject: [PATCH] gonna get this clean one of these days. --- util/basicdefines.hpp | 6 + util/grid/grid3.hpp | 951 +++++--------------------------------- util/grid/gridtest.hpp | 8 +- util/ray3.hpp | 1 + util/vectorlogic/vec3.hpp | 13 +- 5 files changed, 133 insertions(+), 846 deletions(-) create mode 100644 util/basicdefines.hpp diff --git a/util/basicdefines.hpp b/util/basicdefines.hpp new file mode 100644 index 0000000..d71f360 --- /dev/null +++ b/util/basicdefines.hpp @@ -0,0 +1,6 @@ +#ifndef M_PI +#define M_PI 3.14159265358979323846f +#endif +#ifndef EPSILON +#define EPSILON 0.0000000000000000000000001f +#endif diff --git a/util/grid/grid3.hpp b/util/grid/grid3.hpp index 0788956..22ffd28 100644 --- a/util/grid/grid3.hpp +++ b/util/grid/grid3.hpp @@ -7,878 +7,149 @@ #include "../timing_decorator.hpp" #include "../output/frame.hpp" #include "../noise/pnoise2.hpp" +#include "../vecmat/mat4.hpp" #include -#include -#include #include -#include "../ray3.hpp" +#include "../basicdefines.hpp" -constexpr float EPSILON = 0.0000000000000000000000001; -constexpr int CHUNK_SIZE = 16; - -/// @brief Represents a single point in the grid with an ID, color, and position. -class GenericVoxel { -protected: - size_t id; - Vec4ui8 color; - Vec3f pos; -public: - //constructors - GenericVoxel(size_t id, Vec4ui8 color, Vec3f pos) : id(id), color(color), pos(pos) {}; - GenericVoxel() : id(0), color(Vec4ui8()), pos(Vec3f()) {}; - - //getters - size_t getId() const { - return id; - } - Vec3f getPos() const { - return pos; - } - - Vec4ui8 getColor() const { - return color; - } - - //setters - void setColor(Vec4ui8 newColor) { - color = newColor; - } - void setPos(Vec3f newPos) { - pos = newPos; - } - void setId(size_t newId) { - id = newId; - } - - void move(Vec3f newPos) { - pos = newPos; - } - - void recolor(Vec4ui8 newColor) { - color.recolor(newColor); - } +struct Voxel { + float active; + //Vec3f position; + Vec3ui8 color; }; -/// @brief A bidirectional lookup helper to map internal IDs to 2D positions and vice-versa. -/// @details Maintains two hashmaps to allow O(1) lookup in either direction. -class reverselookupassistant3 { +class VoxelGrid { private: - std::unordered_map Positions; - /// "Positions" reversed - stores the reverse mapping from Vec3f to ID. - std::unordered_map ƨnoiƚiƨoꟼ; - size_t next_id; + size_t width, height, depth; + std::vector voxels; public: - /// @brief Get the Position associated with a specific ID. - /// @throws std::out_of_range if the ID does not exist. - Vec3f at(size_t id) const { - auto it = Positions.at(id); - return it; + VoxelGrid(size_t w, size_t h, size_t d) : width(w), height(h), depth(d) { + voxels.resize(w * h * d); } - /// @brief Get the ID associated with a specific Position. - /// @throws std::out_of_range if the Position does not exist. - size_t at(const Vec3f& pos) const { - size_t id = ƨnoiƚiƨoꟼ.at(pos); - return id; + Voxel& get(size_t x, size_t y, size_t z) { + return voxels[z * width * height + y * width + x]; } - /// @brief Finds a position by ID (Wrapper for at). - Vec3f find(size_t id) { - return Positions.at(id); + const Voxel& get(size_t x, size_t y, size_t z) const { + return voxels[z * width * height + y * width + x]; } - /// @brief Registers a new position and assigns it a unique ID. - /// @return The newly generated ID. - size_t set(const Vec3f& pos) { - size_t id = next_id++; - Positions[id] = pos; - ƨnoiƚiƨoꟼ[pos] = id; - return id; + void set(size_t x, size_t y, size_t z, float active, Vec3ui8 color) { + //expand grid if needed. + if (x >= 0 || y >= 0 || z >= 0) { + if (!(x < width)) { + width = x; + voxels.resize(width*height*depth); + } + else if (!(y < height)) { + height = y; + voxels.resize(width*height*depth); + } + else if (!(z < depth)) { + depth = z; + voxels.resize(width*height*depth); + } + + Voxel& v = get(x, y, z); + v.active = std::clamp(active, 0.0f, 1.0f); + v.color = color; + } } - /// @brief Removes an entry by ID. - size_t remove(size_t id) { - Vec3f& pos = Positions[id]; - Positions.erase(id); - ƨnoiƚiƨoꟼ.erase(pos); - return id; + bool inGrid(Vec3T voxl) { + return (voxl > 0 && voxl.x < width && voxl.y < height && voxl.z < depth); } - /// @brief Removes an entry by Position. - size_t remove(const Vec3f& pos) { - size_t id = ƨnoiƚiƨoꟼ[pos]; - Positions.erase(id); - ƨnoiƚiƨoꟼ.erase(pos); - return id; - } + bool rayCast(const Ray3f& ray, float maxDistance, Vec3f hitPos, Vec3f hitNormal, Vec3f& hitColor) { + hitColor = Vec3f(0,0,0); + Vec3f rayDir = ray.direction; + Vec3f rayOrigin = ray.origin; + Vec3T currentVoxel = rayOrigin.floorToT(); - void reserve(size_t size) { - Positions.reserve(size); - ƨnoiƚiƨoꟼ.reserve(size); - } - size_t size() const { - return Positions.size(); - } + //important note: voxels store a float of "active" which is to be between 0 and 1, with ::iterator; - using const_iterator = typename std::unordered_map::const_iterator; + /* + Finally, we compute tDeltaX and tDeltaY. TDeltaX indicates how far along the ray we must move + (in units of t) for the horizontal component of such a movement to equal the width of a voxel. Similarly, + we store in tDeltaY the amount of movement along the ray which has a vertical component equal to the + height of a voxel. + */ - iterator begin() { - return Positions.begin(); - } - iterator end() { - return Positions.end(); - } - const_iterator begin() const { - return Positions.begin(); - } - const_iterator end() const { - return Positions.end(); - } - const_iterator cbegin() const { - return Positions.cbegin(); - } - const_iterator cend() const { - return Positions.cend(); - } + //also include tDeltaZ in this. - bool contains(size_t id) const { - return (Positions.find(id) != Positions.end()); - } - - bool contains(const Vec3f& pos) const { - return (ƨnoiƚiƨoꟼ.find(pos) != ƨnoiƚiƨoꟼ.end()); - } -}; - -class Chunk3 : public GenericVoxel { -private: - Vec3f chunkCoord; - std::unordered_set voxelIDs; - bool isCompressed = false; - int detailLevel; - std::vector fullVoxels; - std::vector compressedVoxels; -public: - //overload GenericVoxel - Vec4ui8 getColor() { - if (isCompressed) { - return color; + /*loop { + if(tMaxX < tMaxY) { + tMaxX= tMaxX + tDeltaX; + X= X + stepX; } else { - if (fullVoxels.empty()) { - return Vec4ui8(); - } - - Vec4ui8 accumulatedColor(0, 0, 0, 0); - - for (const auto& voxel : fullVoxels) { - accumulatedColor = accumulatedColor + voxel.getColor(); - } - - float count = static_cast(fullVoxels.size()); - return accumulatedColor / count; + tMaxY= tMaxY + tDeltaY; + Y= Y + stepY; } - } + NextVoxel(X,Y); + }*/ - Chunk3(const Vec3f& coord) : chunkCoord(coord) {} - - Vec3f getCoord() const { return chunkCoord; } - - std::pair getBounds() const { - Vec3f minBound( - chunkCoord.x*CHUNK_SIZE, - chunkCoord.y*CHUNK_SIZE, - chunkCoord.z*CHUNK_SIZE - ); - Vec3f maxBound( - minBound.x+CHUNK_SIZE, - minBound.y+CHUNK_SIZE, - minBound.z+CHUNK_SIZE - ); - return {minBound, maxBound}; - } - - Vec3f worldToChunkPos(const Vec3f& worldPos) const { - auto [minBound, _] = getBounds(); - return worldPos - minBound; - } - - std::vector compress() { - for (auto value : fullVoxels) { - - - } - } -}; - -/// @brief Accelerates spatial queries by bucketizing positions into a grid. -class SpatialGrid3 { -private: - float cellSize; -public: - std::unordered_map, Vec3f::Hash> grid; - - /// @brief Initializes the spatial grid. - /// @param cellSize The dimension of the spatial buckets. Larger cells mean more items per bucket but fewer buckets. - SpatialGrid3(float cellSize = 2.0f) : cellSize(cellSize) {} - - /// @brief Converts world coordinates to spatial grid coordinates. - Vec3f worldToGrid(const Vec3f& worldPos) const { - return (worldPos / cellSize).floor(); - } - - /// @brief Adds an object ID to the spatial index at the given position. - void insert(size_t id, const Vec3f& pos) { - Vec3f gridPos = worldToGrid(pos); - grid[gridPos].insert(id); - } - - /// @brief Removes an object ID from the spatial index. - void remove(size_t id, const Vec3f& pos) { - Vec3f gridPos = worldToGrid(pos); - auto cellIt = grid.find(gridPos); - if (cellIt != grid.end()) { - cellIt->second.erase(id); - if (cellIt->second.empty()) { - grid.erase(cellIt); - } - } - } - - /// @brief Moves an object within the spatial index (removes from old cell, adds to new if changed). - void update(size_t id, const Vec3f& oldPos, const Vec3f& newPos) { - Vec3f oldGridPos = worldToGrid(oldPos); - Vec3f newGridPos = worldToGrid(newPos); - - if (oldGridPos != newGridPos) { - remove(id, oldPos); - insert(id, newPos); - } - } - - /// @brief Returns all IDs located in the specific grid cell containing 'center'. - std::unordered_set find(const Vec3f& center) const { - auto cellIt = grid.find(worldToGrid(center)); - if (cellIt != grid.end()) { - return cellIt->second; - } - return std::unordered_set(); - } - - /// @brief Finds all object IDs within a square area around the center. - /// @param center The world position center. - /// @param radius The search radius (defines the bounds of grid cells to check). - /// @return A vector of candidate IDs (Note: this returns objects in valid grid cells, further distance checks may be required). - std::vector queryRange(const Vec3f& center, float radius) const { - std::vector results; - float radiusSq = radius * radius; - - // Calculate grid bounds for the query - Vec3f minGrid = worldToGrid(center - Vec3f(radius, radius, radius)); - Vec3f maxGrid = worldToGrid(center + Vec3f(radius, radius, radius)); - - size_t estimatedSize = (maxGrid.x - minGrid.x + 1) * (maxGrid.y - minGrid.y + 1) * (maxGrid.z - minGrid.z + 1) * 10; - results.reserve(estimatedSize); - - // Check all relevant grid cells - for (int x = minGrid.x; x <= maxGrid.x; ++x) { - for (int y = minGrid.y; y <= maxGrid.y; ++y) { - for (int z = minGrid.z; z <= minGrid.z; ++z) { - auto cellIt = grid.find(Vec3f(x, y, z)); - if (cellIt != grid.end()) { - results.insert(results.end(), cellIt->second.begin(), cellIt->second.end()); - } - } - } - } - - return results; - } - - void clear() { - grid.clear(); - grid.rehash(0); - } -}; - -class Grid3 { -protected: - //all positions - reverselookupassistant3 Positions; - std::unordered_map Pixels; - - std::vector unassignedIDs; - - float neighborRadius = 1.0f; - - SpatialGrid3 spatialGrid; - float spatialCellSize = neighborRadius * 1.5f; - - // Default background color for empty spaces - Vec4ui8 defaultBackgroundColor = Vec4ui8(0, 0, 0, 0); - PNoise2 noisegen; - - bool regenpreventer = false; -public: - - Grid3& noiseGenGrid(Vec3f min, Vec3f max, float minChance = 0.1f - , float maxChance = 1.0f, bool color = true, int noisemod = 42) { - TIME_FUNCTION; - noisegen = PNoise2(noisemod); - std::cout << "generating a noise grid with the following: "<< min << " by " << max << "chance min: " << minChance - << " max: " << maxChance << " gen colors: " << color << std::endl; - std::vector poses; - std::vector colors; - #pragma omp parallel for - for (int x = min.x; x < max.x; x++) { - #pragma omp parallel for - for (int y = min.y; y < max.y; y++) { - #pragma omp parallel for - for (int z = min.z; z < max.z; z++) { - float nx = (x+noisemod)/(max.x+EPSILON)/0.1; - float ny = (y+noisemod)/(max.y+EPSILON)/0.1; - float nz = (z+noisemod)/(max.z+EPSILON)/0.1; - Vec3 pos = Vec3f(nx,ny,nz); - float alpha = noisegen.permute(pos); - if (alpha > minChance && alpha < maxChance) { - if (color) { - float red = noisegen.permute(Vec3f(nx, ny, nz)*0.3); - float green = noisegen.permute(Vec3f(nx, ny, nz)*0.6); - float blue = noisegen.permute(Vec3f(nx, ny, nz)*0.9); - Vec4 newc = Vec4ui8(red,green,blue,1.0); - #pragma omp critical - colors.push_back(newc); - #pragma omp critical - poses.push_back(Vec3f(x,y,z)); - } else { - Vec4 newc = Vec4ui8(alpha,alpha,alpha,1.0); - #pragma omp critical - colors.push_back(newc); - #pragma omp critical - poses.push_back(Vec3f(x,y,z)); - } - } - } - } - } - std::cout << "noise generated" << std::endl; - bulkAddObjects(poses,colors); - return *this; - } - - size_t addObject(const Vec3f& pos, const Vec4ui8& color, float size = 1.0f) { - size_t id = Positions.set(pos); - Pixels.emplace(id, GenericVoxel(id, color, pos)); - spatialGrid.insert(id, pos); - return id; - } - - /// @brief Sets the default background color. - void setDefault(const Vec4ui8& color) { - defaultBackgroundColor = color; - } - - /// @brief Moves an object to a new position and updates spatial indexing. - void setPosition(size_t id, const Vec3f& newPosition) { - Vec3f oldPosition = Positions.at(id); - Pixels.at(id).move(newPosition); - spatialGrid.update(id, oldPosition, newPosition); - Positions.at(id).move(newPosition); - } - - void setColor(size_t id, const Vec4ui8 color) { - Pixels.at(id).recolor(color); - } - - void setNeighborRadius(float radius) { - neighborRadius = radius; - //optimizeSpatialGrid(); - } - - Vec4ui8 getDefaultBackgroundColor() const { - return defaultBackgroundColor; - } - - Vec3f getPositionID(size_t id) const { - Vec3f it = Positions.at(id); - return it; - } - - size_t getPositionVec(const Vec3f& pos, float radius = 0.0f) const { - TIME_FUNCTION; - if (radius == 0.0f) { - // Exact match - use spatial grid to find the cell - Vec3f gridPos = spatialGrid.worldToGrid(pos); - auto cellIt = spatialGrid.grid.find(gridPos); - if (cellIt != spatialGrid.grid.end()) { - for (size_t id : cellIt->second) { - if (Positions.at(id) == pos) { - return id; - } - } - } - return -1; + /* + We loop until either we find a voxel with a non-empty object list or we fall out of the end of the grid. + Extending the algorithm to three dimensions simply requires that we add the appropriate z variables and + find the minimum of tMaxX, tMaxY and tMaxZ during each iteration. This results in: + list= NIL; + do { + if(tMaxX < tMaxY) { + if(tMaxX < tMaxZ) { + X= X + stepX; + if(X == justOutX) + return(NIL); + tMaxX= tMaxX + tDeltaX; } else { - auto results = getPositionVecRegion(pos, radius); - if (!results.empty()) { - return results[0]; // Return first found - } - return -1; + Z= Z + stepZ; + if(Z == justOutZ) + return(NIL); + tMaxZ= tMaxZ + tDeltaZ; } - } - - size_t getOrCreatePositionVec(const Vec3f& pos, float radius = 0.0f, bool create = true) { - //TIME_FUNCTION; //called too many times and average time is less than 0.0000001 so ignore it. - if (radius == 0.0f) { - Vec3f gridPos = spatialGrid.worldToGrid(pos); - auto cellIt = spatialGrid.grid.find(gridPos); - if (cellIt != spatialGrid.grid.end()) { - for (size_t id : cellIt->second) { - if (Positions.at(id) == pos) { - return id; - } - } - } - if (create) { - return addObject(pos, defaultBackgroundColor, 1.0f); - } - throw std::out_of_range("Position not found"); } else { - auto results = getPositionVecRegion(pos, radius); - if (!results.empty()) { - return results[0]; - } - if (create) { - return addObject(pos, defaultBackgroundColor, 1.0f); - } - throw std::out_of_range("No positions found in radius"); + if(tMaxY < tMaxZ) { + Y= Y + stepY; + if(Y == justOutY) + return(NIL); + tMaxY= tMaxY + tDeltaY; + } else { + Z= Z + stepZ; + if(Z == justOutZ) + return(NIL); + tMaxZ= tMaxZ + tDeltaZ; } - } - - std::vector getPositionVecRegion(const Vec3f& pos, float radius = 1.0f) const { - //TIME_FUNCTION; - float searchRadius = (radius == 0.0f) ? std::numeric_limits::epsilon() : radius; - - // Get candidates from spatial grid - std::vector candidates = spatialGrid.queryRange(pos, searchRadius); - - // Fine-filter by exact distance - std::vector results; - float radiusSq = searchRadius * searchRadius; - - for (size_t id : candidates) { - if (Positions.at(id).distanceSquared(pos) <= radiusSq) { - results.push_back(id); - } } - - return results; + list= ObjectList[X][Y][Z]; + } while(list == NIL); + return(list);*/ } - - Vec4ui8 getColor(size_t id) { - return Pixels.at(id).getColor(); - } - - std::pair getBoundingBox(Vec3f& minCorner, Vec3f& maxCorner) const { - TIME_FUNCTION; - if (Positions.empty()) { - std::cout << "empty" << std::endl; - minCorner = Vec3f(0, 0, 0); - maxCorner = Vec3f(0, 0, 0); - } - - // Initialize with first position - auto it = Positions.begin(); - minCorner = it->second; - maxCorner = it->second; - - // Find min and max coordinates - for (const auto& [id, pos] : Positions) { - minCorner.x = std::min(minCorner.x, pos.x); - minCorner.y = std::min(minCorner.y, pos.y); - minCorner.z = std::min(minCorner.z, pos.z); - maxCorner.x = std::max(maxCorner.x, pos.x); - maxCorner.y = std::max(maxCorner.y, pos.y); - maxCorner.z = std::max(maxCorner.z, pos.z); - } - // std::cout << "bounding box: " << minCorner << ", " << maxCorner << std::endl; - return std::make_pair(minCorner, maxCorner); - } - - frame getGridRegionAsFrame(const Vec3f& minCorner, const Vec3f& maxCorner, const Vec2& res, - const Ray3& View, frame::colormap outChannels = frame::colormap::RGB) const { - TIME_FUNCTION; - - // Calculate volume dimensions - float width = maxCorner.x - minCorner.x; - float height = maxCorner.y - minCorner.y; - float depth = maxCorner.z - minCorner.z; - - size_t outputWidth = static_cast(res.x); - size_t outputHeight = static_cast(res.y); - - // Validate dimensions - if (width <= 0 || height <= 0 || depth <= 0 || outputWidth <= 0 || outputHeight <= 0) { - frame outframe = frame(); - outframe.colorFormat = outChannels; - return outframe; - } - - frame outframe(outputWidth, outputHeight, outChannels); - - std::unordered_map colorBuffer; - std::unordered_map colorAccumBuffer; - std::unordered_map countBuffer; - std::unordered_map depthBuffer; - - size_t bufferSize = outputWidth * outputHeight; - colorBuffer.reserve(bufferSize); - colorAccumBuffer.reserve(bufferSize); - countBuffer.reserve(bufferSize); - depthBuffer.reserve(bufferSize); - - Vec3f viewDirection = View.direction; - Vec3f viewOrigin = View.origin; - - Vec3f viewRight = Vec3f(1, 0, 0); - Vec3f viewUp = Vec3f(0, 1, 0); - - float xScale = outputWidth / width; - float yScale = outputHeight / height; - - size_t voxelCount = 0; - - for (const auto& [id, pos] : Positions) { - if (pos.x >= minCorner.x && pos.x <= maxCorner.x && - pos.y >= minCorner.y && pos.y <= maxCorner.y && - pos.z >= minCorner.z && pos.z <= maxCorner.z) { - - voxelCount++; - - float relX = pos.x - minCorner.x; - float relY = pos.y - minCorner.y; - float relZ = pos.z - minCorner.z; - - Vec3f toVoxel = pos - viewOrigin; - float distance = toVoxel.length(); - - Vec3f viewPlanePos = pos - (toVoxel.dot(viewDirection)) * viewDirection; - - float screenX = viewPlanePos.dot(viewRight); - float screenY = viewPlanePos.dot(viewUp); - - int pixX = static_cast((screenX - minCorner.x) * xScale); - int pixY = static_cast((screenY - minCorner.y) * yScale); - - pixX = std::max(0, std::min(pixX, static_cast(outputWidth) - 1)); - pixY = std::max(0, std::min(pixY, static_cast(outputHeight) - 1)); - - Vec2 pixelPos(pixX, pixY); - - Vec4ui8 voxelColor = Pixels.at(id).getColor(); - - float depth = relZ; - - - bool shouldRender = true; - auto depthIt = depthBuffer.find(pixelPos); - if (depthIt != depthBuffer.end()) { - if (depth > depthIt->second) { - shouldRender = false; - } else { - depthBuffer[pixelPos] = depth; - } - } else { - depthBuffer[pixelPos] = depth; - } - - if (shouldRender) { - colorAccumBuffer[pixelPos] += voxelColor; - countBuffer[pixelPos]++; - - colorBuffer[pixelPos] = voxelColor; - } - } - } - - switch (outChannels) { - case frame::colormap::RGBA: { - std::vector pixelBuffer(outputWidth * outputHeight * 4, 0); - for (size_t y = 0; y < outputHeight; ++y) { - for (size_t x = 0; x < outputWidth; ++x) { - Vec2 pixelPos(x, y); - size_t index = (y * outputWidth + x) * 4; - - Vec4ui8 finalColor; - auto countIt = countBuffer.find(pixelPos); - - if (countIt != countBuffer.end() && countIt->second > 0) { - finalColor = colorAccumBuffer[pixelPos] / static_cast(countIt->second); - finalColor = finalColor.clamp(0.0f, 1.0f); - finalColor = finalColor * 255.0f; - } else { - finalColor = defaultBackgroundColor * 255.0f; - } - - pixelBuffer[index + 0] = static_cast(finalColor.r); - pixelBuffer[index + 1] = static_cast(finalColor.g); - pixelBuffer[index + 2] = static_cast(finalColor.b); - pixelBuffer[index + 3] = static_cast(finalColor.a); - } - } - - outframe.setData(pixelBuffer); - break; - } - - case frame::colormap::BGR: { - std::vector pixelBuffer(outputWidth * outputHeight * 3, 0); - - for (size_t y = 0; y < outputHeight; ++y) { - for (size_t x = 0; x < outputWidth; ++x) { - Vec2 pixelPos(x, y); - size_t index = (y * outputWidth + x) * 3; - - Vec4ui8 finalColor; - auto countIt = countBuffer.find(pixelPos); - - if (countIt != countBuffer.end() && countIt->second > 0) { - finalColor = colorAccumBuffer[pixelPos] / static_cast(countIt->second); - finalColor = finalColor.clamp(0.0f, 1.0f); - finalColor = finalColor * 255.0f; - } else { - finalColor = defaultBackgroundColor * 255.0f; - } - - pixelBuffer[index + 2] = static_cast(finalColor.r); - pixelBuffer[index + 1] = static_cast(finalColor.g); - pixelBuffer[index + 0] = static_cast(finalColor.b); - } - } - - outframe.setData(pixelBuffer); - break; - } - - case frame::colormap::RGB: - default: { - std::vector pixelBuffer(outputWidth * outputHeight * 3, 0); - - for (size_t y = 0; y < outputHeight; ++y) { - for (size_t x = 0; x < outputWidth; ++x) { - Vec2 pixelPos(x, y); - size_t index = (y * outputWidth + x) * 3; - - Vec4ui8 finalColor; - auto countIt = countBuffer.find(pixelPos); - - if (countIt != countBuffer.end() && countIt->second > 0) { - finalColor = colorAccumBuffer[pixelPos] / static_cast(countIt->second); - finalColor = finalColor.clamp(0.0f, 1.0f); - finalColor = finalColor * 255.0f; - } else { - finalColor = defaultBackgroundColor * 255.0f; - } - - pixelBuffer[index + 0] = static_cast(finalColor.r); - pixelBuffer[index + 1] = static_cast(finalColor.g); - pixelBuffer[index + 2] = static_cast(finalColor.b); - } - } - - outframe.setData(pixelBuffer); - break; - } - } - - return outframe; - } - - frame getGridAsFrame(const Vec2& res, const Ray3& View, frame::colormap outChannels = frame::colormap::RGB) const { - Vec3f Min; - Vec3f Max; - auto a = getBoundingBox(Min, Max); - - return getGridRegionAsFrame(a.first, a.second, res, View, outChannels); - } - - size_t removeID(size_t id) { - Vec3f oldPosition = Positions.at(id); - Positions.remove(id); - Pixels.erase(id); - unassignedIDs.push_back(id); - spatialGrid.remove(id, oldPosition); - return id; - } - - void bulkUpdatePositions(const std::unordered_map& newPositions) { - TIME_FUNCTION; - for (const auto& [id, newPos] : newPositions) { - Vec3f oldPosition = Positions.at(id); - Positions.at(id).move(newPos); - Pixels.at(id).move(newPos); - spatialGrid.update(id, oldPosition, newPos); - } - } - - std::vector bulkAddObjects(const std::vector poses, std::vector colors) { - TIME_FUNCTION; - std::vector ids; - ids.reserve(poses.size()); - - // Reserve space in maps to avoid rehashing - if (Positions.bucket_count() < Positions.size() + poses.size()) { - Positions.reserve(Positions.size() + poses.size()); - Pixels.reserve(Positions.size() + poses.size()); - } - - // Batch insertion - std::vector newids; - for (size_t i = 0; i < poses.size(); ++i) { - size_t id = Positions.set(poses[i]); - Pixels.emplace(id, GenericVoxel(id, colors[i], poses[i])); - spatialGrid.insert(id,poses[i]); - newids.push_back(id); - } - - shrinkIfNeeded(); - - return newids; - } - - void shrinkIfNeeded() { - //TODO: garbage collector - } - - void clear() { - Positions.clear(); - Pixels.clear(); - spatialGrid.clear(); - Pixels.rehash(0); - defaultBackgroundColor = Vec4ui8(0, 0, 0, 0); - } - - void optimizeSpatialGrid() { - TIME_FUNCTION; - //std::cout << "optimizeSpatialGrid()" << std::endl; - spatialCellSize = neighborRadius * neighborRadius; - spatialGrid = SpatialGrid3(spatialCellSize); - - // Rebuild spatial grid - spatialGrid.clear(); - for (const auto& [id, pos] : Positions) { - spatialGrid.insert(id, pos); - } - } - - std::vector getNeighbors(size_t id) const { - Vec3f pos = Positions.at(id); - std::vector candidates = spatialGrid.queryRange(pos, neighborRadius); - std::vector neighbors; - float radiusSq = neighborRadius * neighborRadius; - - for (size_t candidateId : candidates) { - if (candidateId == id) continue; - if (!Positions.contains(candidateId)) continue; - - if (pos.distanceSquared(Positions.at(candidateId)) <= radiusSq) { - if (Pixels.find(candidateId) != Pixels.end()) { - std::cerr << "NOT IN PIXELS! ERROR! ERROR!" < getNeighborsRange(size_t id, float dist) const { - Vec3f pos = Positions.at(id); - std::vector candidates = spatialGrid.queryRange(pos, neighborRadius); - - std::vector neighbors; - float radiusSq = dist * dist; - - for (size_t candidateId : candidates) { - if (candidateId != id && pos.distanceSquared(Positions.at(candidateId)) <= radiusSq) { - neighbors.push_back(candidateId); - } - } - - return neighbors; - } - - Grid3& backfillGrid() { - TIME_FUNCTION; - Vec3f Min; - Vec3f Max; - getBoundingBox(Min, Max); - std::vector newPos; - std::vector newColors; - for (size_t x = Min.x; x < Max.x; x++) { - for (size_t y = Min.y; y < Max.y; y++) { - for (size_t z = Min.z; z < Max.z; z++) { - Vec3f pos = Vec3f(x,y,z); - if (Positions.contains(pos)) continue; - Vec4ui8 color = defaultBackgroundColor; - float size = 0.1; - newPos.push_back(pos); - newColors.push_back(color); - } - } - } - bulkAddObjects(newPos, newColors); - return *this; - } - - bool checkConsistency() const { - std::cout << "=== Consistency Check ===" << std::endl; - std::cout << "Positions size: " << Positions.size() << std::endl; - std::cout << "Pixels size: " << Pixels.size() << std::endl; - - // Check 1: All Pixels should have corresponding Positions - for (const auto& [id, voxel] : Pixels) { - if (!Positions.contains(id)) { - std::cout << "ERROR: Pixel ID " << id << " not in Positions!" << std::endl; - return false; - } - } - - // Check 2: All Positions should have corresponding Pixels (maybe not always true?) - for (const auto& [id, pos] : Positions) { - if (Pixels.find(id) == Pixels.end()) { - std::cout << "ERROR: Position ID " << id << " not in Pixels!" << std::endl; - std::cout << " Position: " << pos << std::endl; - return false; - } - } - - std::cout << "Consistency check passed!" << std::endl; - return true; - } - - }; #endif \ No newline at end of file diff --git a/util/grid/gridtest.hpp b/util/grid/gridtest.hpp index 855287a..154242c 100644 --- a/util/grid/gridtest.hpp +++ b/util/grid/gridtest.hpp @@ -69,7 +69,7 @@ public: if (rayDirection[i] >= 0) { t0[i] = (0 - rayOrigin[i]) / rayDirection[i]; t1[i] = (width - rayOrigin[i]) / rayDirection[i]; - } else { + } else { t0[i] = (width - rayOrigin[i]) / rayDirection[i]; t1[i] = (0 - rayOrigin[i]) / rayDirection[i]; } @@ -84,7 +84,7 @@ public: if (tEnter > 0) { voxel = Vec3f((rayOrigin + rayDirection * tEnter).floor()); - } + } } // Initialize step and tMax based on ray direction @@ -93,7 +93,7 @@ public: step[i] = -1; tMax[i] = ((float)voxel[i] - rayOrigin[i]) / rayDirection[i]; tDelta[i] = -1.0f / rayDirection[i]; - } else { + } else { step[i] = 1; tMax[i] = ((float)(voxel[i] + 1) - rayOrigin[i]) / rayDirection[i]; tDelta[i] = 1.0f / rayDirection[i]; @@ -174,7 +174,7 @@ public: Vec3f up; float fov; - Camera() : position(0, 0, -10), forward(0, 0, 1), up(0, 1, 0), fov(45.0f) {} + Camera() : position(0, 0, -10), forward(0, 0, 1), up(0, 1, 0), fov(80.0f) {} Mat4f getViewMatrix() const { return lookAt(position, position + forward, up); diff --git a/util/ray3.hpp b/util/ray3.hpp index 7d3a684..3157879 100644 --- a/util/ray3.hpp +++ b/util/ray3.hpp @@ -75,5 +75,6 @@ public: }; using Ray3f = Ray3; +using Ray3T = Ray3; #endif \ No newline at end of file diff --git a/util/vectorlogic/vec3.hpp b/util/vectorlogic/vec3.hpp index 979479e..6167e27 100644 --- a/util/vectorlogic/vec3.hpp +++ b/util/vectorlogic/vec3.hpp @@ -186,6 +186,10 @@ public: (x == other.x && y > other.y) || (x == other.x && y == other.y && z > other.z); } + + bool operator>(size_t scalar) const { + return (x > scalar && y > scalar && z > scalar); + } bool operator>=(const Vec3& other) const { return (x > other.x) || @@ -201,8 +205,12 @@ public: return Vec3(std::floor(x), std::floor(y), std::floor(z)); } - Vec3i floorToI() const { - return Vec3i(static_cast(std::floor(x)), static_cast(std::floor(x)), static_cast(std::floor(z))) + Vec3 floorToI() const { + return Vec3(static_cast(std::floor(x)), static_cast(std::floor(x)), static_cast(std::floor(z))); + } + + Vec3 floorToT() const { + return Vec3(static_cast(std::floor(x)), static_cast(std::floor(x)), static_cast(std::floor(z))); } Vec3 ceil() const { @@ -393,6 +401,7 @@ using Vec3f = Vec3; using Vec3d = Vec3; using Vec3i = Vec3; using Vec3ui8 = Vec3; +using Vec3T = Vec3; template inline std::ostream& operator<<(std::ostream& os, const Vec3& vec) {