bunch of fixes to the grid33 version
This commit is contained in:
2
makefile
2
makefile
@@ -16,7 +16,7 @@ PKG_FLAGS := $(LINUX_GL_LIBS) `pkg-config --static --cflags --libs glfw3`
|
|||||||
CXXFLAGS += $(PKG_FLAGS)
|
CXXFLAGS += $(PKG_FLAGS)
|
||||||
|
|
||||||
# Source files
|
# Source files
|
||||||
SRC := $(SRC_DIR)/g3test2.cpp
|
SRC := $(SRC_DIR)/g3test3.cpp
|
||||||
#SRC := $(SRC_DIR)/g2chromatic2.cpp
|
#SRC := $(SRC_DIR)/g2chromatic2.cpp
|
||||||
SRC += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
|
SRC += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
|
||||||
SRC += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp
|
SRC += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp
|
||||||
|
|||||||
1
readme.md
Normal file
1
readme.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Thanks to Treexy, Amanatides, Woo, Occam, Incf, and so on.
|
||||||
137
tests/g3test3.cpp
Normal file
137
tests/g3test3.cpp
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
// test_voxel_render.cpp
|
||||||
|
#include "../util/grid/grid33.hpp"
|
||||||
|
#include "../util/output/bmpwriter.hpp"
|
||||||
|
#include <random>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Initialize random number generator
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
std::uniform_real_distribution<> pos_dist(-1.0, 1.0);
|
||||||
|
std::uniform_int_distribution<> color_dist(0, 255);
|
||||||
|
|
||||||
|
// Create a voxel grid with 0.1 unit resolution
|
||||||
|
VoxelGrid<Vec3ui8, 2, 3> voxelGrid(0.1);
|
||||||
|
|
||||||
|
std::cout << "Placing 10 random colored voxels..." << std::endl;
|
||||||
|
|
||||||
|
// Place 10 random colored voxels
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
// Generate random position
|
||||||
|
double x = pos_dist(gen);
|
||||||
|
double y = pos_dist(gen);
|
||||||
|
double z = pos_dist(gen);
|
||||||
|
|
||||||
|
// Generate random color
|
||||||
|
uint8_t r = static_cast<uint8_t>(color_dist(gen));
|
||||||
|
uint8_t g = static_cast<uint8_t>(color_dist(gen));
|
||||||
|
uint8_t b = static_cast<uint8_t>(color_dist(gen));
|
||||||
|
|
||||||
|
Vec3d worldPos(x, y, z);
|
||||||
|
Vec3ui8 color(r, g, b);
|
||||||
|
|
||||||
|
// Set voxel color
|
||||||
|
bool wasOn = voxelGrid.setVoxelColor(worldPos, color);
|
||||||
|
|
||||||
|
std::cout << "Voxel " << i + 1 << ": "
|
||||||
|
<< "Pos(" << x << ", " << y << ", " << z << ") "
|
||||||
|
<< "Color(RGB:" << static_cast<int>(r) << ","
|
||||||
|
<< static_cast<int>(g) << "," << static_cast<int>(b) << ") "
|
||||||
|
<< (wasOn ? "(overwritten)" : "(new)") << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\nMemory usage: " << voxelGrid.getMemoryUsage() << " bytes" << std::endl;
|
||||||
|
|
||||||
|
// Render to BMP
|
||||||
|
std::cout << "\nRendering orthographic projection to BMP..." << std::endl;
|
||||||
|
|
||||||
|
int width = 512;
|
||||||
|
int height = 512;
|
||||||
|
|
||||||
|
// Create a buffer for the rendered image
|
||||||
|
std::vector<uint8_t> imageBuffer;
|
||||||
|
|
||||||
|
// Render with orthographic projection (view along Z axis)
|
||||||
|
voxelGrid.renderProjectedToRGBBuffer(imageBuffer, width, height,
|
||||||
|
Vec3d(0, 0, 1), // View direction (looking along Z)
|
||||||
|
Vec3d(0, 1, 0)); // Up direction
|
||||||
|
|
||||||
|
std::cout << "Image buffer size: " << imageBuffer.size() << " bytes" << std::endl;
|
||||||
|
std::cout << "Expected size: " << (width * height * 3) << " bytes" << std::endl;
|
||||||
|
|
||||||
|
// Save to BMP using BMPWriter
|
||||||
|
std::string filename = "voxel_render.bmp";
|
||||||
|
|
||||||
|
// Create a frame object from the buffer
|
||||||
|
frame renderFrame(width, height, frame::colormap::RGB);
|
||||||
|
renderFrame.setData(imageBuffer);
|
||||||
|
|
||||||
|
// Save as BMP
|
||||||
|
if (BMPWriter::saveBMP(filename, renderFrame)) {
|
||||||
|
std::cout << "Successfully saved to: " << filename << std::endl;
|
||||||
|
|
||||||
|
// Also save using the direct vector interface as backup
|
||||||
|
if (BMPWriter::saveBMP("voxel_render_direct.bmp", imageBuffer, width, height)) {
|
||||||
|
std::cout << "Also saved direct version: voxel_render_direct.bmp" << std::endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "Failed to save BMP!" << std::endl;
|
||||||
|
|
||||||
|
// Try alternative save method
|
||||||
|
std::cout << "Trying alternative save method..." << std::endl;
|
||||||
|
|
||||||
|
// Convert to Vec3ui8 format
|
||||||
|
std::vector<Vec3ui8> pixelsVec3;
|
||||||
|
pixelsVec3.reserve(width * height);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < imageBuffer.size(); i += 3) {
|
||||||
|
pixelsVec3.push_back(Vec3ui8(
|
||||||
|
imageBuffer[i],
|
||||||
|
imageBuffer[i + 1],
|
||||||
|
imageBuffer[i + 2]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BMPWriter::saveBMP("voxel_render_vec3.bmp", pixelsVec3, width, height)) {
|
||||||
|
std::cout << "Saved Vec3ui8 version: voxel_render_vec3.bmp" << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "All save methods failed!" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test accessor functionality
|
||||||
|
std::cout << "\nTesting accessor functionality..." << std::endl;
|
||||||
|
auto accessor = voxelGrid.createAccessor();
|
||||||
|
|
||||||
|
// Try to retrieve one of the voxels
|
||||||
|
Vec3d testPos(0.0, 0.0, 0.0); // Center point
|
||||||
|
Vec3i testCoord = voxelGrid.posToCoord(testPos);
|
||||||
|
|
||||||
|
Vec3ui8* retrievedColor = voxelGrid.getVoxelColor(testPos);
|
||||||
|
if (retrievedColor) {
|
||||||
|
std::cout << "Found voxel at center: Color(RGB:"
|
||||||
|
<< static_cast<int>(retrievedColor->x) << ","
|
||||||
|
<< static_cast<int>(retrievedColor->y) << ","
|
||||||
|
<< static_cast<int>(retrievedColor->z) << ")" << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "No voxel found at center position" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through all voxels using forEachCell
|
||||||
|
std::cout << "\nIterating through all voxels:" << std::endl;
|
||||||
|
int voxelCount = 0;
|
||||||
|
voxelGrid.forEachCell([&](const Vec3ui8& color, const Vec3i& coord) {
|
||||||
|
Vec3d pos = voxelGrid.Vec3iToPos(coord);
|
||||||
|
std::cout << "Voxel " << ++voxelCount << ": "
|
||||||
|
<< "Coord(" << coord.x << ", " << coord.y << ", " << coord.z << ") "
|
||||||
|
<< "WorldPos(" << pos.x << ", " << pos.y << ", " << pos.z << ") "
|
||||||
|
<< "Color(RGB:" << static_cast<int>(color.x) << ","
|
||||||
|
<< static_cast<int>(color.y) << "," << static_cast<int>(color.z) << ")"
|
||||||
|
<< std::endl;
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "\nTotal voxels in grid: " << voxelCount << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -45,9 +45,7 @@ inline uint32_t CountOn(uint64_t v)
|
|||||||
// Software Implementation
|
// Software Implementation
|
||||||
v = v - ((v >> 1) & uint64_t(0x5555555555555555));
|
v = v - ((v >> 1) & uint64_t(0x5555555555555555));
|
||||||
v = (v & uint64_t(0x3333333333333333)) + ((v >> 2) & uint64_t(0x3333333333333333));
|
v = (v & uint64_t(0x3333333333333333)) + ((v >> 2) & uint64_t(0x3333333333333333));
|
||||||
v = (((v + (v >> 4)) & uint64_t(0xF0F0F0F0F0F0F0F)) *
|
v = (((v + (v >> 4)) & uint64_t(0xF0F0F0F0F0F0F0F)) * uint64_t(0x101010101010101)) >> 56;
|
||||||
uint64_t(0x101010101010101)) >>
|
|
||||||
56;
|
|
||||||
#endif
|
#endif
|
||||||
return static_cast<uint32_t>(v);
|
return static_cast<uint32_t>(v);
|
||||||
}
|
}
|
||||||
@@ -70,7 +68,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t findNextOn(uint32_t start) const {
|
uint32_t findNextOn(uint32_t start) const {
|
||||||
uint32_t n start >> 6;
|
uint32_t n = start >> 6;
|
||||||
if (n >= WORD_COUNT) {
|
if (n >= WORD_COUNT) {
|
||||||
return SIZE;
|
return SIZE;
|
||||||
}
|
}
|
||||||
@@ -126,7 +124,7 @@ public:
|
|||||||
|
|
||||||
Iterator& operator=(const Iterator&) = default;
|
Iterator& operator=(const Iterator&) = default;
|
||||||
|
|
||||||
uint32_t opeator*() const {
|
uint32_t operator*() const {
|
||||||
return mPos;
|
return mPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +136,7 @@ public:
|
|||||||
mPos = mParent -> findNextOn(mPos + 1);
|
mPos = mParent -> findNextOn(mPos + 1);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
Mask() {
|
Mask() {
|
||||||
for (uint32_t i = 0; i < WORD_COUNT; ++i) {
|
for (uint32_t i = 0; i < WORD_COUNT; ++i) {
|
||||||
@@ -269,6 +267,7 @@ public:
|
|||||||
|
|
||||||
template <typename DataT, int Log2DIM>
|
template <typename DataT, int Log2DIM>
|
||||||
class Grid {
|
class Grid {
|
||||||
|
public:
|
||||||
constexpr static int DIM = 1 << Log2DIM;
|
constexpr static int DIM = 1 << Log2DIM;
|
||||||
constexpr static int SIZE = DIM * DIM * DIM;
|
constexpr static int SIZE = DIM * DIM * DIM;
|
||||||
std::array<DataT, SIZE> data;
|
std::array<DataT, SIZE> data;
|
||||||
@@ -277,8 +276,6 @@ class Grid {
|
|||||||
|
|
||||||
template <typename DataT, int INNER_BITS = 2, int LEAF_BITS = 3>
|
template <typename DataT, int INNER_BITS = 2, int LEAF_BITS = 3>
|
||||||
class VoxelGrid {
|
class VoxelGrid {
|
||||||
private:
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr static int32_t Log2N = INNER_BITS + LEAF_BITS;
|
constexpr static int32_t Log2N = INNER_BITS + LEAF_BITS;
|
||||||
using LeafGrid = Grid<DataT, LEAF_BITS>;
|
using LeafGrid = Grid<DataT, LEAF_BITS>;
|
||||||
@@ -310,7 +307,7 @@ public:
|
|||||||
return total_size;
|
return total_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline Veci PosToCoord(float x, float y, float z) {
|
static inline Vec3i PosToCoord(float x, float y, float z) {
|
||||||
// union VI {
|
// union VI {
|
||||||
// __m128i m;
|
// __m128i m;
|
||||||
// int32_t i[4];
|
// int32_t i[4];
|
||||||
@@ -333,7 +330,7 @@ public:
|
|||||||
return pos.floorToI();
|
return pos.floorToI();
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3d Vec3ioPos(const Vec3i &coord) {
|
Vec3d Vec3iToPos(const Vec3i& coord) const {
|
||||||
return (coord.toDouble() * resolution) + half_resolution;
|
return (coord.toDouble() * resolution) + half_resolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,7 +339,10 @@ public:
|
|||||||
constexpr static int32_t MASK_LEAF = ((1 << LEAF_BITS) - 1);
|
constexpr static int32_t MASK_LEAF = ((1 << LEAF_BITS) - 1);
|
||||||
constexpr static int32_t MASK_INNER = ((1 << INNER_BITS) - 1);
|
constexpr static int32_t MASK_INNER = ((1 << INNER_BITS) - 1);
|
||||||
for (auto& map_it : root_map) {
|
for (auto& map_it : root_map) {
|
||||||
const auto& [xA, yA, zA] = (map_it.first);
|
const Vec3i& root_coord = map_it.first;
|
||||||
|
int32_t xA = root_coord.x;
|
||||||
|
int32_t yA = root_coord.y;
|
||||||
|
int32_t zA = root_coord.z;
|
||||||
InnerGrid& inner_grid = map_it.second;
|
InnerGrid& inner_grid = map_it.second;
|
||||||
auto& mask2 = inner_grid.mask;
|
auto& mask2 = inner_grid.mask;
|
||||||
for (auto inner_it = mask2.beginOn(); inner_it; ++inner_it) {
|
for (auto inner_it = mask2.beginOn(); inner_it; ++inner_it) {
|
||||||
@@ -364,7 +364,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Accessor {
|
class Accessor {
|
||||||
private:
|
private:
|
||||||
RootMap &root_;
|
RootMap &root_;
|
||||||
@@ -383,7 +382,7 @@ public:
|
|||||||
if (root_key != prev_root_coord_ || !prev_inner_ptr_) {
|
if (root_key != prev_root_coord_ || !prev_inner_ptr_) {
|
||||||
auto root_it = root_.find(root_key);
|
auto root_it = root_.find(root_key);
|
||||||
if (root_it == root_.end()) {
|
if (root_it == root_.end()) {
|
||||||
root_it = root_insert({root_key, InnerGrid()}).first;
|
root_it = root_.insert({root_key, InnerGrid()}).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
inner_ptr = &(root_it->second);
|
inner_ptr = &(root_it->second);
|
||||||
@@ -426,7 +425,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t inner_index = getInnerIndex(coord);
|
const uint32_t inner_index = getInnerIndex(coord);
|
||||||
auto& inner_data - inner_ptr->data[inner_index];
|
auto& inner_data = inner_ptr->data[inner_index];
|
||||||
|
|
||||||
if (!inner_ptr->mask.isOn(inner_index)) {
|
if (!inner_ptr->mask.isOn(inner_index)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -452,7 +451,7 @@ public:
|
|||||||
const LeafGrid* lastLeafGrid() const {
|
const LeafGrid* lastLeafGrid() const {
|
||||||
return prev_leaf_ptr_;
|
return prev_leaf_ptr_;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
Accessor createAccessor() {
|
Accessor createAccessor() {
|
||||||
return Accessor(root_map);
|
return Accessor(root_map);
|
||||||
@@ -488,4 +487,56 @@ public:
|
|||||||
((coord.z & MASK) << (LEAF_BITS * 2));
|
((coord.z & MASK) << (LEAF_BITS * 2));
|
||||||
// clang-format on
|
// clang-format on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool setVoxelColor(const Vec3d& worldPos, const Vec3ui8& color) {
|
||||||
|
Vec3i coord = posToCoord(worldPos);
|
||||||
|
Accessor accessor = createAccessor();
|
||||||
|
return accessor.setValue(coord, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3ui8* getVoxelColor(const Vec3d& worldPos) {
|
||||||
|
Vec3i coord = posToCoord(worldPos);
|
||||||
|
Accessor accessor = createAccessor();
|
||||||
|
return accessor.value(coord);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render with projection (simple orthographic projection)
|
||||||
|
void renderProjectedToRGBBuffer(std::vector<uint8_t>& buffer, int width, int height, const Vec3d& viewDir = Vec3d(0, 0, 1),
|
||||||
|
const Vec3d& upDir = Vec3d(0, 1, 0)) {
|
||||||
|
// Clear buffer
|
||||||
|
buffer.clear();
|
||||||
|
buffer.resize(width * height * 3, 0);
|
||||||
|
|
||||||
|
// Create view matrix (simplified orthographic projection)
|
||||||
|
Vec3d view = viewDir.normalized();
|
||||||
|
Vec3d up = upDir.normalized();
|
||||||
|
Vec3d right = view.cross(up).normalized();
|
||||||
|
up = right.cross(view).normalized(); // Re-orthogonalize
|
||||||
|
|
||||||
|
// For each voxel, project to screen
|
||||||
|
forEachCell([&](const Vec3ui8& color, const Vec3i& coord) {
|
||||||
|
// Convert voxel coordinate to world position
|
||||||
|
Vec3d worldPos = Vec3iToPos(coord);
|
||||||
|
|
||||||
|
// Simple orthographic projection: drop view direction component
|
||||||
|
double xProj = worldPos.dot(right);
|
||||||
|
double yProj = worldPos.dot(up);
|
||||||
|
|
||||||
|
// Normalize to pixel coordinates (assuming unit size)
|
||||||
|
int px = static_cast<int>((xProj + 0.5) * width);
|
||||||
|
int py = static_cast<int>((yProj + 0.5) * height);
|
||||||
|
|
||||||
|
// Clamp to image bounds
|
||||||
|
if (px >= 0 && px < width && py >= 0 && py < height) {
|
||||||
|
int index = (py * width + px) * 3;
|
||||||
|
|
||||||
|
Vec3ui8 finalColor = color;
|
||||||
|
|
||||||
|
// Write RGB
|
||||||
|
buffer[index] = finalColor.x; // R
|
||||||
|
buffer[index + 1] = finalColor.y; // G
|
||||||
|
buffer[index + 2] = finalColor.z; // B
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include "vec2.hpp"
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class Vec3 {
|
class Vec3 {
|
||||||
|
|||||||
Reference in New Issue
Block a user