diff --git a/examples/cornell_box_metal_sphere b/examples/cornell_box_metal_sphere index b83fcc8..ca2c8b7 100644 Binary files a/examples/cornell_box_metal_sphere and b/examples/cornell_box_metal_sphere differ diff --git a/examples/cornell_box_metal_sphere.cpp b/examples/cornell_box_metal_sphere.cpp index 599cce9..e97e4cd 100644 --- a/examples/cornell_box_metal_sphere.cpp +++ b/examples/cornell_box_metal_sphere.cpp @@ -299,7 +299,7 @@ void setup_cornell_box() { g_scene->add_mesh(tall_box); // Metal sphere (replacing the glass box, positioned on the right side) - auto metal_sphere = create_sphere(0.5f, 64, 32, /*metal_id*/white_id); + auto metal_sphere = create_sphere(0.5f, 32, 16, /*metal_id*/white_id); metal_sphere->set_position(Vec3(0.55f, -1.5f, 0.35f)); metal_sphere->upload_to_gpu(); g_scene->add_mesh(metal_sphere); @@ -529,12 +529,12 @@ int main() { ARE_LOG_INFO("Initializing renderer..."); RendererConfig config; - config.width_ = WINDOW_WIDTH; - config.height_ = WINDOW_HEIGHT; - config.samples_per_pixel_ = 1; - config.max_ray_depth_ = 4; - config.enable_accumulation_ = true; - config.enable_denoising_ = false; + config.output_width = WINDOW_WIDTH; + config.output_height = WINDOW_HEIGHT; + config.rt_config.samples_per_pixel = 1; + config.rt_config.max_depth = 4; + config.rt_config.enable_accumulation = true; + config.enable_denoising = false; g_renderer = std::make_unique(config); if (!g_renderer->initialize()) { diff --git a/include/core/raytracer.h b/include/core/raytracer.h index 5049a21..c6a2a32 100644 --- a/include/core/raytracer.h +++ b/include/core/raytracer.h @@ -7,21 +7,12 @@ #include "resource/buffer.h" #include "resource/shader.h" #include "scene/scene.h" +#include "utils/config.h" #include #include namespace are { -// Ray tracing configuration -struct RayTracerConfig { - uint samples_per_pixel_; - uint max_depth_; - bool enable_shadows_; - bool enable_reflections_; - bool enable_accumulation_; - bool use_bvh_; -}; - // Compute shader based ray tracer class RayTracer { public: diff --git a/include/utils/config.h b/include/utils/config.h index d80d4ab..b7a5137 100644 --- a/include/utils/config.h +++ b/include/utils/config.h @@ -6,14 +6,25 @@ namespace are { +// Ray tracing configuration +struct RayTracerConfig { + uint samples_per_pixel = 1; + uint max_depth = 4; + bool enable_shadows = true; + bool enable_reflections = true; + bool enable_accumulation = true; + bool use_bvh = true; +}; + + // Configuration struct for renderer struct RendererConfig { - uint width_; - uint height_; - uint samples_per_pixel_; - uint max_ray_depth_; - bool enable_denoising_; - bool enable_accumulation_; + uint output_width; + uint output_height; + RayTracerConfig rt_config; + bool enable_denoising; + bool enable_sr; // Enable the super resolution mode + double sr_scaling; // The magnification of super-resolution }; } // namespace are diff --git a/src/core/raytracer.cpp b/src/core/raytracer.cpp index 0204285..1668855 100644 --- a/src/core/raytracer.cpp +++ b/src/core/raytracer.cpp @@ -84,7 +84,7 @@ bool RayTracer::initialize(const std::shared_ptr &shader) { } // Initialize BVH if enabled - if (config_.use_bvh_) { + if (config_.use_bvh) { bvh_ = std::make_unique(); } @@ -134,7 +134,7 @@ void RayTracer::release() { } bool RayTracer::rebuild_bvh(const Scene &scene) { - if (!config_.use_bvh_) { + if (!config_.use_bvh) { ARE_LOG_WARN("BVH is disabled in configuration"); return false; } @@ -173,7 +173,7 @@ void RayTracer::trace(const Scene &scene, const GBuffer &gbuffer, TextureHandle } // Build BVH if enabled and not built yet - if (config_.use_bvh_ && !bvh_built_) { + if (config_.use_bvh && !bvh_built_) { rebuild_bvh(scene); } @@ -222,7 +222,7 @@ void RayTracer::trace(const Scene &scene, const GBuffer &gbuffer, TextureHandle glBindImageTexture(4, accumulation_texture_, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F); // Bind BVH buffers if enabled - if (config_.use_bvh_ && bvh_built_) { + if (config_.use_bvh && bvh_built_) { bvh_node_buffer_.bind_base(2); bvh_triangle_buffer_.bind_base(3); bvh_attr_buffer_.bind_base(4); @@ -234,10 +234,10 @@ void RayTracer::trace(const Scene &scene, const GBuffer &gbuffer, TextureHandle // Set uniforms compute_shader_->set_uint("u_frame_count", frame_count_); - compute_shader_->set_uint("u_samples_per_pixel", config_.samples_per_pixel_); - compute_shader_->set_uint("u_max_depth", config_.max_depth_); + compute_shader_->set_uint("u_samples_per_pixel", config_.samples_per_pixel); + compute_shader_->set_uint("u_max_depth", config_.max_depth); compute_shader_->set_uint("u_light_count", static_cast(scene.get_lights().size())); - compute_shader_->set_bool("u_enable_accumulation", config_.enable_accumulation_); + compute_shader_->set_bool("u_enable_accumulation", config_.enable_accumulation); // Enable/disable textures based on material usage compute_shader_->set_bool("u_enable_textures", has_textures); @@ -257,7 +257,7 @@ void RayTracer::trace(const Scene &scene, const GBuffer &gbuffer, TextureHandle glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); // Increment frame count for accumulation - if (config_.enable_accumulation_) { + if (config_.enable_accumulation) { frame_count_++; } } @@ -288,16 +288,16 @@ void RayTracer::reset_accumulation() { } void RayTracer::set_config(const RayTracerConfig &config) { - bool bvh_changed = (config.use_bvh_ != config_.use_bvh_); + bool bvh_changed = (config.use_bvh != config_.use_bvh); config_ = config; reset_accumulation(); if (bvh_changed) { - if (config_.use_bvh_ && !bvh_) { + if (config_.use_bvh && !bvh_) { bvh_ = std::make_unique(); bvh_built_ = false; - } else if (!config_.use_bvh_) { + } else if (!config_.use_bvh) { bvh_.reset(); bvh_built_ = false; } diff --git a/src/core/renderer.cpp b/src/core/renderer.cpp index c127cf7..590cbca 100644 --- a/src/core/renderer.cpp +++ b/src/core/renderer.cpp @@ -18,54 +18,48 @@ Renderer::~Renderer() { } bool Renderer::initialize() { - if (initialized_) { - ARE_LOG_WARN("Renderer already initialized"); - return true; - } - - ARE_LOG_INFO("Initializing Aurora Rendering Engine..."); - - // Initialize shader manager - shader_manager_ = std::make_unique(); - if (!shader_manager_->initialize()) { - ARE_LOG_ERROR("Failed to initialize shader manager"); - return false; - } - - // Initialize G-Buffer - gbuffer_ = std::make_unique(config_.width_, config_.height_); - if (!gbuffer_->initialize()) { - ARE_LOG_ERROR("Failed to initialize G-Buffer"); - return false; - } - - // Initialize ray tracer - RayTracerConfig rt_config; - rt_config.samples_per_pixel_ = config_.samples_per_pixel_; - rt_config.max_depth_ = config_.max_ray_depth_; - rt_config.enable_shadows_ = true; - rt_config.enable_reflections_ = true; - rt_config.enable_accumulation_ = config_.enable_accumulation_; - rt_config.use_bvh_ = true; - + if (initialized_) { + ARE_LOG_WARN("Renderer already initialized"); + return true; + } + + ARE_LOG_INFO("Initializing Aurora Rendering Engine..."); + + // Initialize shader manager + shader_manager_ = std::make_unique(); + if (!shader_manager_->initialize()) { + ARE_LOG_ERROR("Failed to initialize shader manager"); + return false; + } + + // Initialize G-Buffer + gbuffer_ = std::make_unique(config_.output_width, config_.output_height); + if (!gbuffer_->initialize()) { + ARE_LOG_ERROR("Failed to initialize G-Buffer"); + return false; + } + // Initialize ray tracer - raytracer_ = std::make_unique(config_.width_, config_.height_, rt_config); - const auto& rt_shader = shader_manager_->get_raytracing_shader(); - if (!raytracer_->initialize(rt_shader)) { - ARE_LOG_ERROR("Failed to initialize ray tracer"); - return false; - } + RayTracerConfig rt_config = config_.rt_config; - // Initialize screen blit - screen_blit_ = std::make_unique(); - const auto& screen_blit_shader = shader_manager_->get_screen_blit_shader(); - if (!screen_blit_->initialize(screen_blit_shader)) { - ARE_LOG_ERROR("Failed to initialize screen blit"); - return false; - } + // Initialize ray tracer + raytracer_ = std::make_unique(config_.output_width, config_.output_height, rt_config); + const auto &rt_shader = shader_manager_->get_raytracing_shader(); + if (!raytracer_->initialize(rt_shader)) { + ARE_LOG_ERROR("Failed to initialize ray tracer"); + return false; + } - denoiser_ = std::make_unique(config_.width_, config_.height_); - const auto& denoise_shader = shader_manager_->get_denoise_shader(); + // Initialize screen blit + screen_blit_ = std::make_unique(); + const auto &screen_blit_shader = shader_manager_->get_screen_blit_shader(); + if (!screen_blit_->initialize(screen_blit_shader)) { + ARE_LOG_ERROR("Failed to initialize screen blit"); + return false; + } + + denoiser_ = std::make_unique(config_.output_width, config_.output_height); + const auto &denoise_shader = shader_manager_->get_denoise_shader(); if (!denoiser_->initialize(denoise_shader)) { ARE_LOG_ERROR("Failed to initialize denoiser"); return false; @@ -73,7 +67,7 @@ bool Renderer::initialize() { // Create ray tracing output texture (reused every frame) ResourceManager &rm = ResourceManager::instance(); - rt_output_texture_ = rm.create_texture(config_.width_, config_.height_, TextureFormat::RGBA32F); + rt_output_texture_ = rm.create_texture(config_.output_width, config_.output_height, TextureFormat::RGBA32F); initialized_ = true; ARE_LOG_INFO("Aurora Rendering Engine initialized successfully"); @@ -103,79 +97,79 @@ void Renderer::shutdown() { ARE_LOG_INFO("Aurora Rendering Engine shut down"); } -RenderStats Renderer::render(const Scene& scene, TextureHandle output_texture) { - RenderStats stats = {}; - - if (!initialized_) { - ARE_LOG_ERROR("Renderer not initialized"); - return stats; - } - - // Start timing - auto start_time = std::chrono::high_resolution_clock::now(); - - // Phase 1: G-Buffer pass - auto gbuffer_start = std::chrono::high_resolution_clock::now(); - - const auto& gbuffer_shader = shader_manager_->get_gbuffer_shader(); +RenderStats Renderer::render(const Scene &scene, TextureHandle output_texture) { + RenderStats stats = {}; + + if (!initialized_) { + ARE_LOG_ERROR("Renderer not initialized"); + return stats; + } + + // Start timing + auto start_time = std::chrono::high_resolution_clock::now(); + + // Phase 1: G-Buffer pass + auto gbuffer_start = std::chrono::high_resolution_clock::now(); + + const auto &gbuffer_shader = shader_manager_->get_gbuffer_shader(); if (!gbuffer_shader || !gbuffer_shader->is_valid()) { ARE_LOG_ERROR("G-Buffer shader is invalid"); return stats; } gbuffer_->render(scene, *gbuffer_shader); - - auto gbuffer_end = std::chrono::high_resolution_clock::now(); - stats.gbuffer_time_ms_ = std::chrono::duration(gbuffer_end - gbuffer_start).count(); - - // Phase 2: Ray tracing pass - auto raytrace_start = std::chrono::high_resolution_clock::now(); - - // Use output texture if provided, otherwise use internal texture - TextureHandle rt_output = (output_texture != 0) ? output_texture : rt_output_texture_; - - raytracer_->trace(scene, *gbuffer_, rt_output); - - auto raytrace_end = std::chrono::high_resolution_clock::now(); - stats.raytrace_time_ms_ = std::chrono::duration(raytrace_end - raytrace_start).count(); - + + auto gbuffer_end = std::chrono::high_resolution_clock::now(); + stats.gbuffer_time_ms_ = std::chrono::duration(gbuffer_end - gbuffer_start).count(); + + // Phase 2: Ray tracing pass + auto raytrace_start = std::chrono::high_resolution_clock::now(); + + // Use output texture if provided, otherwise use internal texture + TextureHandle rt_output = (output_texture != 0) ? output_texture : rt_output_texture_; + + raytracer_->trace(scene, *gbuffer_, rt_output); + + auto raytrace_end = std::chrono::high_resolution_clock::now(); + stats.raytrace_time_ms_ = std::chrono::duration(raytrace_end - raytrace_start).count(); + // Phase 3: Denoise texture TextureHandle final_output = rt_output; - if (config_.enable_denoising_ && denoiser_) { + if (config_.enable_denoising && denoiser_) { // Use temporal accumulation with weight 0.1 (10% blend of new frame) float temporal_weight = 0.1f; final_output = denoiser_->denoise(rt_output, 1, temporal_weight); } - // Phase 4: Blit to screen if output is default framebuffer + // Phase 4: Blit to screen if output is default framebuffer if (output_texture == 0) { screen_blit_->blit_fullscreen(final_output); } - - // Calculate total frame time - auto end_time = std::chrono::high_resolution_clock::now(); - stats.frame_time_ms_ = std::chrono::duration(end_time - start_time).count(); - - // Count triangles - const auto& meshes = scene.get_meshes(); - for (const auto& mesh : meshes) { - stats.triangle_count_ += mesh->get_indices().size() / 3; - } - - // Estimate ray count (very rough) - stats.ray_count_ = config_.width_ * config_.height_ * config_.samples_per_pixel_ * config_.max_ray_depth_; - - frame_count_++; - - return stats; + + // Calculate total frame time + auto end_time = std::chrono::high_resolution_clock::now(); + stats.frame_time_ms_ = std::chrono::duration(end_time - start_time).count(); + + // Count triangles + const auto &meshes = scene.get_meshes(); + for (const auto &mesh : meshes) { + stats.triangle_count_ += mesh->get_indices().size() / 3; + } + + // Estimate ray count (very rough) + stats.ray_count_ = config_.output_width * config_.output_height * config_.rt_config.samples_per_pixel * config_.rt_config.max_depth; + + frame_count_++; + + return stats; } void Renderer::resize(uint width, uint height) { - if (width == config_.width_ && height == config_.height_) + if (width == config_.output_width && height == config_.output_height) return; - config_.width_ = width; - config_.height_ = height; + config_.output_width = width; + config_.output_height = height; if (initialized_) { ResourceManager &rm = ResourceManager::instance(); @@ -195,21 +189,17 @@ void Renderer::resize(uint width, uint height) { } void Renderer::set_config(const RendererConfig &config) { - bool size_changed = (config.width_ != config_.width_ || config.height_ != config_.height_); + bool size_changed = (config.output_width != config_.output_width || config.output_height != config_.output_height); config_ = config; if (initialized_) { if (size_changed) { - resize(config_.width_, config_.height_); + resize(config_.output_width, config_.output_height); } // Update ray tracer config - RayTracerConfig rt_config = raytracer_->get_config(); - rt_config.samples_per_pixel_ = config_.samples_per_pixel_; - rt_config.max_depth_ = config_.max_ray_depth_; - rt_config.enable_accumulation_ = config_.enable_accumulation_; - raytracer_->set_config(rt_config); + raytracer_->set_config(config_.rt_config); } }