diff --git a/h.cpp b/h.cpp index 147f50b..832ec9e 100644 --- a/h.cpp +++ b/h.cpp @@ -1,29 +1,114 @@ #include "util/grid/gridtest.hpp" +#include +#include +#include "util/output/bmpwriter.hpp" -int main() { - VoxelRenderer renderer; +// Function to create a randomized voxel grid +std::unique_ptr createRandomizedGrid(int width, int height, int depth, float density = 0.2f) { + auto grid = std::make_unique(width, height, depth); - // Simple test - // std::cout << "Voxel Grid: " << renderer.getGrid().getWidth() << "x" - // << renderer.getGrid().getHeight() << "x" - // << renderer.getGrid().getDepth() << std::endl; + // Set up random number generation + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution dist(0.0f, 1.0f); + std::uniform_real_distribution colorDist(0.2f, 1.0f); - // Test ray from center - Vec3f rayOrigin(5, 5, -5); - Vec3f rayDir(0, 0, 1); - Vec3f hitPos, hitNormal, hitColor; - - if (renderer.getGrid().rayCast(rayOrigin, rayDir, 20.0f, hitPos, hitNormal, hitColor)) { - std::cout << "Test ray hit at: " << hitPos.x << ", " - << hitPos.y << ", " << hitPos.z << std::endl; - std::cout << "Hit color: " << hitColor.r << ", " - << hitColor.g << ", " << hitColor.b << std::endl; - } else { - std::cout << "Test ray missed" << std::endl; + // Fill grid with random active voxels + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + for (int z = 0; z < depth; z++) { + if (dist(gen) < density) { + // Random color + Vec3f color(colorDist(gen), colorDist(gen), colorDist(gen)); + grid->set(x, y, z, true, color); + } + } + } } - // Render a simple 100x100 "image" - renderer.render(100, 100); + return grid; +} + +// Create a simple structure to hold camera position and orientation +struct CameraPose { + Vec3f position; + Vec3f target; + Vec3f up; +}; + +int main() { + // Create a randomized voxel grid (15x15x15 with 20% density) + const int gridSize = 128; + auto grid = createRandomizedGrid(gridSize, gridSize, gridSize, 0.2f); + + // Create a renderer with our custom grid + VoxelRenderer renderer; + renderer.getGrid() = *grid; // Replace the default test pattern + + // Define 6 camera positions (looking at the center from each axis direction) + std::vector cameraPoses = { + // Front (looking along negative Z) + {Vec3f(0, 0, -gridSize * 2), Vec3f(0, 0, 0), Vec3f(0, 1, 0)}, + + // Back (looking along positive Z) + {Vec3f(0, 0, gridSize * 2), Vec3f(0, 0, 0), Vec3f(0, 1, 0)}, + + // Right (looking along positive X) + {Vec3f(gridSize * 2, 0, 0), Vec3f(0, 0, 0), Vec3f(0, 1, 0)}, + + // Left (looking along negative X) + {Vec3f(-gridSize * 2, 0, 0), Vec3f(0, 0, 0), Vec3f(0, 1, 0)}, + + // Top (looking along negative Y) + {Vec3f(0, gridSize * 2, 0), Vec3f(0, 0, 0), Vec3f(0, 0, -1)}, + + // Bottom (looking along positive Y) + {Vec3f(0, -gridSize * 2, 0), Vec3f(0, 0, 0), Vec3f(0, 0, 1)} + }; + + // Render settings + const int screenWidth = 400; + const int screenHeight = 400; + + // Vector to store all frames + std::vector frames; + + std::cout << "Rendering voxel grid from 6 directions..." << std::endl; + + // Render from each camera position + for (size_t i = 0; i < cameraPoses.size(); i++) { + auto& pose = cameraPoses[i]; + + // Update camera position + renderer.getCamera().position = pose.position; + + // Calculate forward direction (from position to target) + Vec3f forward = (pose.target - pose.position).normalized(); + + // Set camera orientation + renderer.getCamera().forward = forward; + renderer.getCamera().up = pose.up; + + std::cout << "Rendering view " << (i+1) << "/6 from position (" + << pose.position.x << ", " << pose.position.y << ", " << pose.position.z << ")" << std::endl; + + // Render and add to frames vector + frames.push_back(renderer.renderToFrame(screenWidth, screenHeight)); + } + + // Print frame information + std::cout << "\nRendering complete!" << std::endl; + std::cout << "Number of frames created: " << frames.size() << std::endl; + + for (size_t i = 0; i < frames.size(); i++) { + std::cout << "Frame " << (i+1) << ": " << frames[i] << std::endl; + } + + // Optional: Save frames to files if your frame class supports it + for (size_t i = 0; i < frames.size(); i++) { + std::string filename = "output/voxel_view_" + std::to_string(i+1) + ".bmp"; + BMPWriter::saveBMP(filename, frames[i]); + } return 0; } \ No newline at end of file diff --git a/util/grid/gridtest.hpp b/util/grid/gridtest.hpp index fbb9f8e..1dad111 100644 --- a/util/grid/gridtest.hpp +++ b/util/grid/gridtest.hpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include "../output/frame.hpp" struct Voxel { bool active; @@ -14,10 +14,10 @@ struct Voxel { class VoxelGrid { private: - int width, height, depth; - std::vector voxels; public: + int width, height, depth; + std::vector voxels; VoxelGrid(int w, int h, int d) : width(w), height(h), depth(d) { voxels.resize(w * h * d); // Initialize all voxels as inactive @@ -70,7 +70,7 @@ public: Vec3f& hitPos, Vec3f& hitNormal, Vec3f& hitColor) const { // Initialize step directions - Vec3i step; + Vec3f step; Vec3f tMax, tDelta; // Current voxel coordinates @@ -203,15 +203,20 @@ public: // Simple renderer using ray casting class VoxelRenderer { private: - VoxelGrid grid; - Camera camera; public: + VoxelGrid grid; + Camera camera; VoxelRenderer() : grid(20, 20, 20) { grid.createTestPattern(); } - void render(int screenWidth, int screenHeight) { + // Render to a frame object + frame renderToFrame(int screenWidth, int screenHeight) { + + // Create a frame with RGBA format for color + potential transparency + frame renderedFrame(screenWidth, screenHeight, frame::colormap::RGBA); + float aspectRatio = float(screenWidth) / float(screenHeight); // Get matrices @@ -219,6 +224,15 @@ public: Mat4f view = camera.getViewMatrix(); Mat4f invViewProj = (projection * view).inverse(); + // Get reference to frame data for direct pixel writing + std::vector& frameData = const_cast&>(renderedFrame.getData()); + + // Background color (dark gray) + Vec3f backgroundColor(0.1f, 0.1f, 0.1f); + + // Simple light direction + Vec3f lightDir = Vec3f(1, 1, -1).normalized(); + for (int y = 0; y < screenHeight; y++) { for (int x = 0; x < screenWidth; x++) { // Convert screen coordinates to normalized device coordinates @@ -242,21 +256,58 @@ public: Vec3f rayEnd = Vec3f(rayEndWorld.x, rayEndWorld.y, rayEndWorld.z); Vec3f rayDir = (rayEnd - rayStart).normalized(); - // Perform ray casting (use camera position as ray origin) + // Perform ray casting Vec3f hitPos, hitNormal, hitColor; - if (grid.rayCast(camera.position, rayDir, 100.0f, hitPos, hitNormal, hitColor)) { + bool hit = grid.rayCast(camera.position, rayDir, 100.0f, hitPos, hitNormal, hitColor); + + // Calculate pixel index in frame data + int pixelIndex = (y * screenWidth + x) * 4; // 4 channels for RGBA + + if (hit) { // Simple lighting - Vec3f lightDir = Vec3f(1, 1, -1).normalized(); - float diffuse = std::max(static_cast(hitNormal.dot(lightDir)), 0.2f); + float diffuse = std::max(hitNormal.dot(lightDir), 0.2f); - // Output pixel (simplified - in real OpenGL, set pixel color) + // Apply lighting to color + Vec3f finalColor = hitColor * diffuse; + + // Clamp color values to [0, 1] + finalColor.x = std::max(0.0f, std::min(1.0f, finalColor.x)); + finalColor.y = std::max(0.0f, std::min(1.0f, finalColor.y)); + finalColor.z = std::max(0.0f, std::min(1.0f, finalColor.z)); + + // Convert to 8-bit RGB and set pixel + frameData[pixelIndex] = static_cast(finalColor.x * 255); // R + frameData[pixelIndex + 1] = static_cast(finalColor.y * 255); // G + frameData[pixelIndex + 2] = static_cast(finalColor.z * 255); // B + frameData[pixelIndex + 3] = 255; // A (fully opaque) + + // Debug: mark center pixel with a crosshair if (x == screenWidth/2 && y == screenHeight/2) { + // White crosshair for center + frameData[pixelIndex] = 255; + frameData[pixelIndex + 1] = 255; + frameData[pixelIndex + 2] = 255; std::cout << "Center ray hit at: " << hitPos.x << ", " << hitPos.y << ", " << hitPos.z << std::endl; } + } else { + // Background color + frameData[pixelIndex] = static_cast(backgroundColor.x * 255); + frameData[pixelIndex + 1] = static_cast(backgroundColor.y * 255); + frameData[pixelIndex + 2] = static_cast(backgroundColor.z * 255); + frameData[pixelIndex + 3] = 255; // A } } } + + return renderedFrame; + } + + // Overload for backward compatibility (calls the new method and discards frame) + void render(int screenWidth, int screenHeight) { + frame tempFrame = renderToFrame(screenWidth, screenHeight); + // Optional: print info about the rendered frame + std::cout << "Rendered frame: " << tempFrame << std::endl; } void rotateCamera(float yaw, float pitch) { @@ -268,4 +319,7 @@ public: } Camera& getCamera() { return camera; } -}; + + // Get reference to the voxel grid (for testing/debugging) + VoxelGrid& getGrid() { return grid; } +}; \ No newline at end of file diff --git a/util/ray3.hpp b/util/ray3.hpp index cbb5eb1..7d3a684 100644 --- a/util/ray3.hpp +++ b/util/ray3.hpp @@ -63,11 +63,11 @@ public: return crossProduct.length() / direction.length(); } - Ray3 transform(const class Mat4& matrix) const { - Vec3 transformedOrigin = matrix.transformPoint(origin); - Vec3 transformedDirection = matrix.transformDirection(direction); - return Ray3(transformedOrigin, transformedDirection.normalized()); - } + // Ray3 transform(const Mat4& matrix) const { + // Vec3 transformedOrigin = matrix.transformPoint(origin); + // Vec3 transformedDirection = matrix.transformDirection(direction); + // return Ray3(transformedOrigin, transformedDirection.normalized()); + // } std::string toString() const { return "Ray3(origin: " + origin.toString() + ", direction: " + direction.toString() + ")"; diff --git a/util/vectorlogic/vec3.hpp b/util/vectorlogic/vec3.hpp index dd37e19..6d15e83 100644 --- a/util/vectorlogic/vec3.hpp +++ b/util/vectorlogic/vec3.hpp @@ -5,6 +5,7 @@ #include #include #include +#include template class Vec3 { @@ -14,7 +15,7 @@ public: Vec3() : x(0), y(0), z(0) {} Vec3(T x, T y, T z) : x(x), y(y), z(z) {} Vec3(T scalar) : x(scalar), y(scalar), z(scalar) {} - Vec3(float[3] acd) : x(acd[0]), y(acd[1]), z(acd[2]) {} + Vec3(float acd[3]) : x(acd[0]), y(acd[1]), z(acd[2]) {} Vec3(const class Vec2& vec2, T z = 0); @@ -127,7 +128,7 @@ public: return x * other.x + y * other.y + z * other.z; } - Vec3& cross(const Vec3& other) const { + Vec3 cross(const Vec3& other) const { return Vec3( y * other.z - z * other.y, z * other.x - x * other.z,