From 7d174816febeed6977a7e90be5c80e9b99b11df9 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Tue, 14 May 2024 19:58:40 -0400 Subject: [PATCH] many changes, more controls --- .gitignore | 1 + Makefile | 5 +++-- main.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++------------ vec3.h | 6 +++++- view.h | 4 ++-- 5 files changed, 57 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index aedd486..2b90f68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ *.o +*.png *.sw* main imgui.ini diff --git a/Makefile b/Makefile index 838da7e..9c5a43a 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,10 @@ CXXFLAGS := -std=c++23 -O3 -ggdb -g3 -march=native -mtune=native `sdl2-config --cflags` -Iimgui -Iimgui/backends -LDFLAGS := `sdl2-config --libs` +LDFLAGS := `sdl2-config --libs` -lSDL2_image all: main -main: imgui/imgui.o imgui/imgui_draw.o imgui/imgui_widgets.o imgui/imgui_tables.o imgui/backends/imgui_impl_sdl2.o imgui/backends/imgui_impl_sdlrenderer2.o +main: main.cpp imgui/imgui.o imgui/imgui_draw.o imgui/imgui_widgets.o imgui/imgui_tables.o imgui/backends/imgui_impl_sdl2.o imgui/backends/imgui_impl_sdlrenderer2.o + g++ $(CXXFLAGS) $^ $(LDFLAGS) -o main image.ppm: main time ./main > image.ppm diff --git a/main.cpp b/main.cpp index 034aefa..bd749ab 100644 --- a/main.cpp +++ b/main.cpp @@ -1,7 +1,7 @@ constexpr unsigned Width = 1000; constexpr double Aspect = 16.0 / 9.0; constexpr unsigned Height = Width / Aspect; -constexpr unsigned Threads = 8; +constexpr unsigned Threads = 3; #include "color.h" #include "ray.h" @@ -15,6 +15,7 @@ constexpr unsigned Threads = 8; #include "imgui_impl_sdl2.h" #include "imgui_impl_sdlrenderer2.h" #include +#include #include #include @@ -23,10 +24,10 @@ constexpr unsigned Threads = 8; #include #include -static World world; - static View Camera; +static World world; static int SamplesPerPixel = 20; +static float Daylight = 0.5f; static std::unique_ptr> renderer; static std::chrono::time_point renderStart; static std::chrono::duration renderTime; @@ -37,6 +38,7 @@ static void initiateRender(SDL_Surface *canvas); int main() { SDL_Init(SDL_INIT_VIDEO); + IMG_Init(IMG_INIT_PNG); auto window = SDL_CreateWindow("raytrace", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, Width, Height, SDL_WINDOW_RESIZABLE); auto canvas = SDL_CreateRGBSurfaceWithFormat(0, Width, Height, 32, SDL_PIXELFORMAT_RGBA8888); auto painter = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC /*| SDL_RENDERER_ACCELERATED*/); @@ -52,6 +54,7 @@ int main() std::cout << "Spawning threads..." << std::endl; initiateRender(canvas); + auto tex = SDL_CreateTextureFromSurface(painter, canvas); std::cout << "Entering render..." << std::endl; bool run = true; @@ -74,55 +77,85 @@ int main() ImGui::SameLine(); ImGui::SetNextItemWidth(100); ImGui::InputDouble("Y", &Camera.camera.y(), 0.1, 0.05, "%.2lf"); ImGui::SameLine(); ImGui::SetNextItemWidth(100); ImGui::InputDouble("Z", &Camera.camera.z(), 0.1, 0.05, "%.2lf"); ImGui::SliderInt("samples", &SamplesPerPixel, 1, 200); + ImGui::SliderFloat("shade", &Daylight, 0.f, 1.f); if (ImGui::Button("recalculate")) { initiateRender(canvas); } ImGui::SameLine(); + if (ImGui::Button("export")) { + std::string filename ("screenshot_"); + filename += std::to_string(int(randomN() * 1000000)); + filename += ".png"; + IMG_SavePNG(canvas, filename.c_str()); + std::cout << "saved " << filename << std::endl; + } + ImGui::SameLine(); if (ImGui::Button("exit")) { renderer->stop(); run = false; } if (*renderer) { + SDL_DestroyTexture(tex); + tex = SDL_CreateTextureFromSurface(painter, canvas); + ImGui::SameLine(); if (ImGui::Button("stop")) { renderer->stop(); } ImGui::Text("wait... %u%%", renderer->progress()); } else if (renderTime == std::chrono::duration::zero()) { + SDL_DestroyTexture(tex); + tex = SDL_CreateTextureFromSurface(painter, canvas); + renderTime = std::chrono::high_resolution_clock::now() - renderStart; } else { ImGui::Text("%0.6lfs", renderTime.count()); } ImGui::End(); - ImGui::Begin("balls", nullptr, ImGuiWindowFlags_AlwaysAutoResize); { + ImGui::Begin("balls", nullptr, ImGuiWindowFlags_NoResize); { char radius[] = "radius 0"; char mat[] = "mat 0"; char xpos[] = "x 0"; char ypos[] = "y 0"; char zpos[] = "z 0"; + for (auto& o : std::views::drop(world.objects, 1)) { - ImGui::Combo(mat, reinterpret_cast(&o.M), "Lambertian\0Metal\0Dielectric\0"); - ImGui::SameLine(); ImGui::SetNextItemWidth(100); ImGui::InputDouble(radius, &o.radius, 0.1, 0.05, "%.2lf"); - ImGui::SetNextItemWidth(100); ImGui::InputDouble(xpos, &o.center.x(), 0.05, 0.05, "%.2lf"); - ImGui::SameLine(); ImGui::SetNextItemWidth(100); ImGui::InputDouble(ypos, &o.center.y(), 0.1, 0.05, "%.2lf"); - ImGui::SameLine(); ImGui::SetNextItemWidth(100); ImGui::InputDouble(zpos, &o.center.z(), 0.1, 0.05, "%.2lf"); + ImGui::SetNextItemWidth(200); + ImGui::Combo(mat, reinterpret_cast(&o.M), + "Lambertian\0Metal\0Dielectric\0"); + ImGui::SameLine(); ImGui::SetNextItemWidth(100); + ImGui::InputDouble(radius, &o.radius, 0.1, 0.05, "%.2lf"); + ImGui::SetNextItemWidth(100); + ImGui::InputDouble(xpos, &o.center.x(), 0.05, 0.05, "%.2lf"); + ImGui::SameLine(); ImGui::SetNextItemWidth(100); + ImGui::InputDouble(ypos, &o.center.y(), 0.1, 0.05, "%.2lf"); + ImGui::SameLine(); ImGui::SetNextItemWidth(100); + ImGui::InputDouble(zpos, &o.center.z(), 0.1, 0.05, "%.2lf"); + radius[7]++; mat[4]++; xpos[2]++; ypos[2]++; zpos[2]++; } + if (ImGui::Button("add")) { + const point3 pos = vec3::random() * vec3(4, 1.5, 4) - vec3(2, 0, 4); + const color col = vec3::random(); + world.add(pos, randomN() * 0.5 + 0.1, Material::Lambertian, col); + initiateRender(canvas); + } + if (ImGui::Button("del")) { + world.objects.pop_back(); + initiateRender(canvas); + } } ImGui::End(); - auto tex = SDL_CreateTextureFromSurface(painter, canvas); - ImGui::Render(); SDL_RenderClear(painter); SDL_RenderCopy(painter, tex, nullptr, nullptr); ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData()); SDL_RenderPresent(painter); - SDL_DestroyTexture(tex); std::this_thread::sleep_for(std::chrono::milliseconds(30)); } @@ -148,7 +181,7 @@ color ray_color(const ray& r, int depth) return atten * ray_color(scat, depth - 1); } else { const auto unitDir = r.direction().normalize(); - const auto a = 0.5 * (unitDir.y() + 1.0); + const auto a = Daylight * (unitDir.y() + 1.0); return (1.0 - a) * color(1.0, 1.0, 1.0) + a * color(0.5, 0.7, 1.0); } } diff --git a/vec3.h b/vec3.h index 46367d2..b648ce3 100644 --- a/vec3.h +++ b/vec3.h @@ -94,6 +94,10 @@ struct vec3 { auto rpara = v * -std::sqrt(std::fabs(1.0 - rperp.length_squared())); return rperp + rpara; } + + static vec3 random() { + return vec3(randomN(), randomN(), randomN()); + } }; // point3 is just an alias for vec3, but useful for geometric clarity in the code. @@ -125,7 +129,7 @@ inline constexpr vec3 unit_vector(const vec3& v) { inline vec3 randomUnitSphere() { for (;;) { - if (auto p = vec3(randomN(), randomN(), randomN()) * 2 - vec3(1, 1, 1); p.length_squared() < 1) + if (auto p = vec3::random() * 2 - vec3(1, 1, 1); p.length_squared() < 1) return p; } } diff --git a/view.h b/view.h index e27176e..0f97358 100644 --- a/view.h +++ b/view.h @@ -12,11 +12,11 @@ struct View static constexpr auto vup = vec3(0, 1, 0); // Camera-relative "up" direction float fieldOfView = 90.f; + point3 camera {0, 0.5, 0.5}; + float focalLength; float viewportHeight; float viewportWidth; - - point3 camera; vec3 viewportX; vec3 viewportY; vec3 pixelDX;