done with trying to copy treexy. it wasnt better after I implemented it. going to switch back to my method.
This commit is contained in:
1
.gitmodules
vendored
1
.gitmodules
vendored
@@ -4,3 +4,4 @@
|
|||||||
[submodule "stb"]
|
[submodule "stb"]
|
||||||
path = stb
|
path = stb
|
||||||
url = https://github.com/nothings/stb
|
url = https://github.com/nothings/stb
|
||||||
|
|
||||||
@@ -1,9 +1,41 @@
|
|||||||
// test_voxel_render.cpp
|
|
||||||
#include "../util/grid/grid33.hpp"
|
#include "../util/grid/grid33.hpp"
|
||||||
|
//#include "../util/grid/treexy/treexy_serialization.hpp"
|
||||||
#include "../util/output/bmpwriter.hpp"
|
#include "../util/output/bmpwriter.hpp"
|
||||||
|
#include "../util/noise/pnoise2.hpp"
|
||||||
|
#include "../util/timing_decorator.cpp"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
struct configuration {
|
||||||
|
float threshold = 0.1;
|
||||||
|
int gridWidth = 128;
|
||||||
|
int gridHeight = 128;
|
||||||
|
int gridDepth = 128;
|
||||||
|
PNoise2 noise = PNoise2(42);
|
||||||
|
};
|
||||||
|
|
||||||
|
void setup(configuration& config, VoxelGrid<Vec3ui8, 2, 3>& grid) {
|
||||||
|
TIME_FUNCTION;
|
||||||
|
uint8_t thresh = config.threshold * 255;
|
||||||
|
for (int z = 0; z < config.gridDepth; ++z) {
|
||||||
|
if (z % 64 == 0) {
|
||||||
|
std::cout << "Processing layer " << z << " of " << config.gridDepth << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0; y < config.gridHeight; ++y) {
|
||||||
|
for (int x = 0; x < config.gridWidth; ++x) {
|
||||||
|
uint8_t r = std::clamp(config.noise.permute(Vec3f(static_cast<float>(x) / config.gridWidth / 64, static_cast<float>(y) / config.gridHeight / 64, static_cast<float>(z) / config.gridDepth / 64)), 0.f, 1.f) * 255;
|
||||||
|
uint8_t g = std::clamp(config.noise.permute(Vec3f(static_cast<float>(x) / config.gridWidth / 32, static_cast<float>(y) / config.gridHeight / 32, static_cast<float>(z) / config.gridDepth / 32)), 0.f, 1.f) * 255;
|
||||||
|
uint8_t b = std::clamp(config.noise.permute(Vec3f(static_cast<float>(x) / config.gridWidth / 16, static_cast<float>(y) / config.gridHeight / 16, static_cast<float>(z) / config.gridDepth / 16)), 0.f, 1.f) * 255;
|
||||||
|
uint8_t a = std::clamp(config.noise.permute(Vec3f(static_cast<float>(x) / config.gridWidth / 8 , static_cast<float>(y) / config.gridHeight / 8 , static_cast<float>(z) / config.gridDepth / 8 )), 0.f, 1.f) * 255;
|
||||||
|
if (a > thresh) {
|
||||||
|
bool wasOn = grid.setVoxelColor(Vec3d(x,y,z), Vec3ui8(r,g,b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// Initialize random number generator
|
// Initialize random number generator
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
@@ -14,32 +46,8 @@ int main() {
|
|||||||
// Create a voxel grid with 0.1 unit resolution
|
// Create a voxel grid with 0.1 unit resolution
|
||||||
VoxelGrid<Vec3ui8, 2, 3> voxelGrid(0.1);
|
VoxelGrid<Vec3ui8, 2, 3> voxelGrid(0.1);
|
||||||
|
|
||||||
std::cout << "Placing 10 random colored voxels..." << std::endl;
|
configuration config;
|
||||||
|
setup(config, voxelGrid);
|
||||||
// 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;
|
std::cout << "\nMemory usage: " << voxelGrid.getMemoryUsage() << " bytes" << std::endl;
|
||||||
|
|
||||||
@@ -53,15 +61,16 @@ int main() {
|
|||||||
std::vector<uint8_t> imageBuffer;
|
std::vector<uint8_t> imageBuffer;
|
||||||
|
|
||||||
// Render with orthographic projection (view along Z axis)
|
// Render with orthographic projection (view along Z axis)
|
||||||
voxelGrid.renderProjectedToRGBBuffer(imageBuffer, width, height,
|
Vec3d camPos = Vec3d(config.gridDepth, config.gridHeight, config.gridWidth * 2);
|
||||||
Vec3d(0, 0, 1), // View direction (looking along Z)
|
Vec3d lookAt = Vec3d(config.gridDepth / 2, config.gridHeight / 2, config.gridWidth / 2);
|
||||||
Vec3d(0, 1, 0)); // Up direction
|
Vec3d viewDir = (lookAt-camPos).normalized();
|
||||||
|
voxelGrid.renderToRGB(imageBuffer, width, height, camPos, viewDir, Vec3d(0, 1, 0), 80.f);
|
||||||
|
|
||||||
std::cout << "Image buffer size: " << imageBuffer.size() << " bytes" << std::endl;
|
std::cout << "Image buffer size: " << imageBuffer.size() << " bytes" << std::endl;
|
||||||
std::cout << "Expected size: " << (width * height * 3) << " bytes" << std::endl;
|
std::cout << "Expected size: " << (width * height * 3) << " bytes" << std::endl;
|
||||||
|
|
||||||
// Save to BMP using BMPWriter
|
// Save to BMP using BMPWriter
|
||||||
std::string filename = "voxel_render.bmp";
|
std::string filename = "output/voxel_render.bmp";
|
||||||
|
|
||||||
// Create a frame object from the buffer
|
// Create a frame object from the buffer
|
||||||
frame renderFrame(width, height, frame::colormap::RGB);
|
frame renderFrame(width, height, frame::colormap::RGB);
|
||||||
@@ -71,33 +80,8 @@ int main() {
|
|||||||
if (BMPWriter::saveBMP(filename, renderFrame)) {
|
if (BMPWriter::saveBMP(filename, renderFrame)) {
|
||||||
std::cout << "Successfully saved to: " << filename << std::endl;
|
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 {
|
} else {
|
||||||
std::cout << "Failed to save BMP!" << std::endl;
|
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
|
// Test accessor functionality
|
||||||
@@ -132,6 +116,7 @@ int main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
std::cout << "\nTotal voxels in grid: " << voxelCount << std::endl;
|
std::cout << "\nTotal voxels in grid: " << voxelCount << std::endl;
|
||||||
|
FunctionTimer::printStats(FunctionTimer::Mode::ENHANCED);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "../vectorlogic/vec3.hpp"
|
#include "../vectorlogic/vec3.hpp"
|
||||||
#include "../basicdefines.hpp"
|
#include "../basicdefines.hpp"
|
||||||
|
#include "../timing_decorator.hpp"
|
||||||
|
|
||||||
/// @brief Finds the index of the least significant bit set to 1 in a 64-bit integer.
|
/// @brief Finds the index of the least significant bit set to 1 in a 64-bit integer.
|
||||||
/// @details Uses compiler intrinsics (_BitScanForward64, __builtin_ctzll) where available,
|
/// @details Uses compiler intrinsics (_BitScanForward64, __builtin_ctzll) where available,
|
||||||
@@ -659,7 +660,7 @@ public:
|
|||||||
/// @param fov the field of view for the camera
|
/// @param fov the field of view for the camera
|
||||||
void renderToRGB(std::vector<uint8_t>& buffer, int width, int height, const Vec3d& viewOrigin,
|
void renderToRGB(std::vector<uint8_t>& buffer, int width, int height, const Vec3d& viewOrigin,
|
||||||
const Vec3d& viewDir, const Vec3d& upDir, float fov = 80) {
|
const Vec3d& viewDir, const Vec3d& upDir, float fov = 80) {
|
||||||
// Resize buffer to hold width * height * 3 bytes (RGB)
|
TIME_FUNCTION;
|
||||||
buffer.resize(width * height * 3);
|
buffer.resize(width * height * 3);
|
||||||
std::fill(buffer.begin(), buffer.end(), 0);
|
std::fill(buffer.begin(), buffer.end(), 0);
|
||||||
|
|
||||||
@@ -674,14 +675,11 @@ public:
|
|||||||
// Compute focal length based on FOV
|
// Compute focal length based on FOV
|
||||||
double aspectRatio = static_cast<double>(width) / static_cast<double>(height);
|
double aspectRatio = static_cast<double>(width) / static_cast<double>(height);
|
||||||
double fovRad = fov * M_PI / 180.0;
|
double fovRad = fov * M_PI / 180.0;
|
||||||
double focalLength = 1.0 / tan(fovRad * 0.5);
|
double focalLength = 0.5 / tan(fovRad * 0.5); // Reduced for wider view
|
||||||
|
|
||||||
// Precompute scaling factors for screen coordinates
|
// Pixel to world scaling
|
||||||
double pixelWidth = 2.0 / (width - 1);
|
double pixelWidth = 2.0 * focalLength / width;
|
||||||
double pixelHeight = 2.0 / (height - 1);
|
double pixelHeight = 2.0 * focalLength / height;
|
||||||
|
|
||||||
// Compute half voxel size for accurate ray-voxel intersection
|
|
||||||
double halfVoxel = resolution * 0.5;
|
|
||||||
|
|
||||||
// Create an accessor for efficient voxel lookup
|
// Create an accessor for efficient voxel lookup
|
||||||
Accessor accessor = createAccessor();
|
Accessor accessor = createAccessor();
|
||||||
@@ -689,81 +687,55 @@ public:
|
|||||||
// For each pixel in the output image
|
// For each pixel in the output image
|
||||||
for (int y = 0; y < height; ++y) {
|
for (int y = 0; y < height; ++y) {
|
||||||
for (int x = 0; x < width; ++x) {
|
for (int x = 0; x < width; ++x) {
|
||||||
// Convert pixel coordinates to normalized device coordinates [-1, 1]
|
// Calculate pixel position in camera space
|
||||||
double ndcX = (2.0 * x / (width - 1)) - 1.0;
|
double u = (x - width * 0.5) * pixelWidth;
|
||||||
double ndcY = 1.0 - (2.0 * y / (height - 1)); // Flip Y
|
double v = (height * 0.5 - y) * pixelHeight;
|
||||||
|
|
||||||
// Scale by aspect ratio
|
// Compute ray direction in world space
|
||||||
ndcX *= aspectRatio;
|
Vec3d rayDirWorld = viewDirN * focalLength +
|
||||||
|
rightDir * u +
|
||||||
// Compute ray direction in camera space
|
realUpDir * v;
|
||||||
Vec3d rayDirCam(ndcX, ndcY, focalLength);
|
|
||||||
|
|
||||||
// Transform ray direction to world space
|
|
||||||
Vec3d rayDirWorld = (rightDir * rayDirCam.x) +
|
|
||||||
(realUpDir * rayDirCam.y) +
|
|
||||||
(viewDirN * rayDirCam.z);
|
|
||||||
rayDirWorld = rayDirWorld.normalized();
|
rayDirWorld = rayDirWorld.normalized();
|
||||||
|
|
||||||
// Set up ray marching
|
// Set up ray marching
|
||||||
Vec3d rayPos = viewOrigin;
|
Vec3d rayPos = viewOrigin;
|
||||||
double maxDistance = 100.0; // Maximum ray distance
|
double maxDistance = 1000.0; // Increased maximum ray distance
|
||||||
double stepSize = resolution; // Step size for ray marching
|
double stepSize = resolution * 0.5; // Smaller step size
|
||||||
|
|
||||||
// Ray marching loop
|
// Ray marching loop
|
||||||
for (double t = 0; t < maxDistance; t += stepSize) {
|
bool hit = false;
|
||||||
|
for (double t = 0; t < maxDistance && !hit; t += stepSize) {
|
||||||
rayPos = viewOrigin + rayDirWorld * t;
|
rayPos = viewOrigin + rayDirWorld * t;
|
||||||
|
|
||||||
|
// Check if we're inside the grid bounds
|
||||||
|
if (rayPos.x < 0 || rayPos.y < 0 || rayPos.z < 0 ||
|
||||||
|
rayPos.x >= 128 || rayPos.y >= 128 || rayPos.z >= 128) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Convert world position to voxel coordinate
|
// Convert world position to voxel coordinate
|
||||||
Vec3i coord = posToCoord(rayPos);
|
Vec3i coord = posToCoord(rayPos);
|
||||||
|
|
||||||
// Look up voxel value using accessor (cached for efficiency)
|
// Look up voxel value using accessor
|
||||||
DataT* voxelData = accessor.value(coord);
|
DataT* voxelData = accessor.value(coord);
|
||||||
|
|
||||||
if (voxelData) {
|
if (voxelData) {
|
||||||
// Voxel hit - extract color
|
// Voxel hit - extract color
|
||||||
// Assuming DataT is Vec3ui8 or compatible
|
|
||||||
Vec3ui8* colorPtr = reinterpret_cast<Vec3ui8*>(voxelData);
|
Vec3ui8* colorPtr = reinterpret_cast<Vec3ui8*>(voxelData);
|
||||||
|
|
||||||
// Get buffer index for this pixel
|
// Get buffer index for this pixel
|
||||||
size_t pixelIdx = (y * width + x) * 3;
|
size_t pixelIdx = (y * width + x) * 3;
|
||||||
|
|
||||||
// Apply simple shading based on normal
|
// Simple distance-based attenuation
|
||||||
// Estimate normal by checking neighbors
|
double distance = t;
|
||||||
double shading = 1.0;
|
double attenuation = 1.0 / (1.0 + distance * 0.01);
|
||||||
|
|
||||||
// Check neighboring voxels to estimate surface normal
|
// Store color in buffer with attenuation
|
||||||
Vec3d voxelCenter = Vec3iToPos(coord);
|
buffer[pixelIdx] = static_cast<uint8_t>(colorPtr->x * attenuation);
|
||||||
Vec3d toRay = (rayPos - voxelCenter).normalized();
|
buffer[pixelIdx + 1] = static_cast<uint8_t>(colorPtr->y * attenuation);
|
||||||
|
buffer[pixelIdx + 2] = static_cast<uint8_t>(colorPtr->z * attenuation);
|
||||||
// Simple normal estimation by checking adjacent voxels
|
|
||||||
Vec3i neighbors[6] = {
|
|
||||||
Vec3i(coord.x + 1, coord.y, coord.z),
|
|
||||||
Vec3i(coord.x - 1, coord.y, coord.z),
|
|
||||||
Vec3i(coord.x, coord.y + 1, coord.z),
|
|
||||||
Vec3i(coord.x, coord.y - 1, coord.z),
|
|
||||||
Vec3i(coord.x, coord.y, coord.z + 1),
|
|
||||||
Vec3i(coord.x, coord.y, coord.z - 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Count empty neighbors to estimate surface orientation
|
|
||||||
int emptyCount = 0;
|
|
||||||
for (int i = 0; i < 6; ++i) {
|
|
||||||
if (!accessor.value(neighbors[i])) {
|
|
||||||
emptyCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple shading: more visible if fewer neighbors (edge/corner)
|
|
||||||
if (emptyCount > 0) {
|
|
||||||
shading = 0.7 + 0.3 * (emptyCount / 6.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store color in buffer with shading
|
|
||||||
buffer[pixelIdx] = static_cast<uint8_t>(colorPtr->x * shading);
|
|
||||||
buffer[pixelIdx + 1] = static_cast<uint8_t>(colorPtr->y * shading);
|
|
||||||
buffer[pixelIdx + 2] = static_cast<uint8_t>(colorPtr->z * shading);
|
|
||||||
|
|
||||||
|
hit = true;
|
||||||
break; // Stop ray marching after hitting first voxel
|
break; // Stop ray marching after hitting first voxel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user