Refractor&Add: 使用shared_ptr优化Shader管理、添加基于G-Buffer的光线追踪、添加场景重建API

master
ternaryop8479 2026-02-11 00:27:37 +08:00
parent 52c6ace2cd
commit b8ae9808a8
12 changed files with 457 additions and 364 deletions

Binary file not shown.

View File

@ -442,7 +442,7 @@ int main() {
RendererConfig config; RendererConfig config;
config.width_ = WINDOW_WIDTH; config.width_ = WINDOW_WIDTH;
config.height_ = WINDOW_HEIGHT; config.height_ = WINDOW_HEIGHT;
config.samples_per_pixel_ = 1; config.samples_per_pixel_ = 4;
config.max_ray_depth_ = 4; config.max_ray_depth_ = 4;
config.enable_accumulation_ = false; config.enable_accumulation_ = false;
config.enable_denoising_ = false; config.enable_denoising_ = false;

View File

@ -7,6 +7,7 @@
#include "resource/buffer.h" #include "resource/buffer.h"
#include "resource/shader.h" #include "resource/shader.h"
#include "scene/scene.h" #include "scene/scene.h"
#include <memory>
namespace are { namespace are {
@ -70,14 +71,14 @@ public:
/// @brief Set compute shader (called by renderer) /// @brief Set compute shader (called by renderer)
/// @param shader Compute shader /// @param shader Compute shader
void set_compute_shader(const Shader &shader); void set_compute_shader(const std::shared_ptr<Shader>& shader);
private: private:
uint width_; uint width_;
uint height_; uint height_;
RayTracerConfig config_; RayTracerConfig config_;
Shader compute_shader_; std::shared_ptr<Shader> compute_shader_;
TextureHandle accumulation_texture_; TextureHandle accumulation_texture_;
BufferHandle scene_buffer_; BufferHandle scene_buffer_;
BufferHandle material_buffer_; BufferHandle material_buffer_;

View File

@ -57,6 +57,9 @@ public:
/// @param config New configuration /// @param config New configuration
void set_config(const RendererConfig& config); void set_config(const RendererConfig& config);
/// @brief Notify scene changed to rebuild acceleration
void notify_scene_changed(const Scene &scene);
private: private:
RendererConfig config_; RendererConfig config_;
std::unique_ptr<GBuffer> gbuffer_; std::unique_ptr<GBuffer> gbuffer_;

View File

@ -5,6 +5,7 @@
#include "resource/shader.h" #include "resource/shader.h"
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
#include <memory>
namespace are { namespace are {
@ -29,7 +30,7 @@ public:
/// @param vertex_path Vertex shader file path /// @param vertex_path Vertex shader file path
/// @param fragment_path Fragment shader file path /// @param fragment_path Fragment shader file path
/// @return Shader object /// @return Shader object
Shader load_shader(const std::string& name, std::shared_ptr<Shader> load_shader(const std::string& name,
const std::string& vertex_path, const std::string& vertex_path,
const std::string& fragment_path); const std::string& fragment_path);
@ -37,26 +38,26 @@ public:
/// @param name Shader name for caching /// @param name Shader name for caching
/// @param compute_path Compute shader file path /// @param compute_path Compute shader file path
/// @return Shader object /// @return Shader object
Shader load_compute_shader(const std::string& name, std::shared_ptr<Shader> load_compute_shader(const std::string& name,
const std::string& compute_path); const std::string& compute_path);
/// @brief Get cached shader by name /// @brief Get cached shader by name
/// @param name Shader name /// @param name Shader name
/// @return Shader object (invalid if not found) /// @return Shader object (invalid if not found)
Shader get_shader(const std::string& name) const; std::shared_ptr<Shader> get_shader(const std::string& name) const;
/// @brief Get G-Buffer shader /// @brief Get G-Buffer shader
/// @return G-Buffer shader /// @return G-Buffer shader
const Shader& get_gbuffer_shader() const { return gbuffer_shader_; } const std::shared_ptr<Shader>& get_gbuffer_shader() const { return gbuffer_shader_; }
/// @brief Get ray tracing compute shader /// @brief Get ray tracing compute shader
/// @return Ray tracing shader /// @return Ray tracing shader
const Shader& get_raytracing_shader() const { return raytracing_shader_; } const std::shared_ptr<Shader>& get_raytracing_shader() const { return raytracing_shader_; }
private: private:
std::unordered_map<std::string, Shader> shader_cache_; std::unordered_map<std::string, std::shared_ptr<Shader>> shader_cache_;
Shader gbuffer_shader_; std::shared_ptr<Shader> gbuffer_shader_;
Shader raytracing_shader_; std::shared_ptr<Shader> raytracing_shader_;
bool initialized_; bool initialized_;

View File

@ -13,6 +13,12 @@ public:
/// @brief Constructor /// @brief Constructor
Shader(); Shader();
Shader(const Shader&) = delete;
Shader& operator=(const Shader&) = delete;
Shader(Shader&& other) noexcept;
Shader& operator=(Shader&& other) noexcept;
/// @brief Destructor /// @brief Destructor
~Shader(); ~Shader();

View File

@ -22,7 +22,7 @@ layout(binding = 0, rgba32f) uniform readonly image2D g_position;
layout(binding = 1, rgba32f) uniform readonly image2D g_normal; layout(binding = 1, rgba32f) uniform readonly image2D g_normal;
layout(binding = 2, rgba8) uniform readonly image2D g_albedo; layout(binding = 2, rgba8) uniform readonly image2D g_albedo;
// New: material params + material id // Material params + material id (for primary hit fast-path)
layout(binding = 5, rgba32f) uniform readonly image2D g_material; layout(binding = 5, rgba32f) uniform readonly image2D g_material;
layout(binding = 6, r32ui) uniform readonly uimage2D g_material_id; layout(binding = 6, r32ui) uniform readonly uimage2D g_material_id;
@ -96,7 +96,6 @@ uniform uint u_frame_count;
uniform uint u_samples_per_pixel; uniform uint u_samples_per_pixel;
uniform uint u_max_depth; uniform uint u_max_depth;
uniform uint u_light_count; uniform uint u_light_count;
uniform vec3 u_camera_position;
uniform mat4 u_inv_view_projection; uniform mat4 u_inv_view_projection;
uniform bool u_enable_accumulation; uniform bool u_enable_accumulation;
uniform bool u_use_bvh; uniform bool u_use_bvh;
@ -234,7 +233,6 @@ bool intersect_triangle(Ray ray, TriangleGpu tri, inout HitInfo hit) {
float t = dot(e2, qvec) * inv_det; float t = dot(e2, qvec) * inv_det;
if (t < EPSILON || t >= hit.t) return false; if (t < EPSILON || t >= hit.t) return false;
// Interpolate normal/uv
float w = 1.0 - u - v; float w = 1.0 - u - v;
vec3 n0 = tri.n0.xyz; vec3 n0 = tri.n0.xyz;
vec3 n1 = tri.n1.xyz; vec3 n1 = tri.n1.xyz;
@ -265,7 +263,6 @@ HitInfo trace_ray_bvh(Ray ray) {
return hit; return hit;
} }
// Small fixed stack
uint stack[64]; uint stack[64];
int sp = 0; int sp = 0;
stack[sp++] = 0u; stack[sp++] = 0u;
@ -288,11 +285,8 @@ HitInfo trace_ray_bvh(Ray ray) {
intersect_triangle(ray, tri, hit); intersect_triangle(ray, tri, hit);
} }
} else { } else {
// Interior: push children
uint left = left_first; uint left = left_first;
uint right = left_first + 1u; uint right = left_first + 1u;
// Depth-first; no sorting (simple)
if (sp < 63) stack[sp++] = right; if (sp < 63) stack[sp++] = right;
if (sp < 63) stack[sp++] = left; if (sp < 63) stack[sp++] = left;
} }
@ -330,9 +324,7 @@ bool trace_any_bvh(Ray ray, float t_max) {
if (count > 0u) { if (count > 0u) {
for (uint i = 0u; i < count; ++i) { for (uint i = 0u; i < count; ++i) {
TriangleGpu tri = bvh_tris[left_first + i]; TriangleGpu tri = bvh_tris[left_first + i];
if (intersect_triangle(ray, tri, hit)) { if (intersect_triangle(ray, tri, hit)) return true;
return true;
}
} }
} else { } else {
uint left = left_first; uint left = left_first;
@ -345,6 +337,45 @@ bool trace_any_bvh(Ray ray, float t_max) {
return false; return false;
} }
// ============================================================================
// Primary-ray fast path via G-Buffer
// ============================================================================
/**
* @brief Read primary hit from G-Buffer if current pixel has geometry
* @note Uses g_position.w as "valid" marker (your gbuffer writes 1.0 on hits, clear is 0).
*/
HitInfo trace_primary_gbuffer(Ray ray, ivec2 pixel_coords) {
HitInfo hit;
hit.hit = false;
hit.t = MAX_FLOAT;
hit.position = vec3(0.0);
hit.normal = vec3(0.0, 1.0, 0.0);
hit.texcoord = vec2(0.0);
hit.material_id = 0u;
vec4 pos = imageLoad(g_position, pixel_coords);
if (pos.w <= 0.5) {
return hit;
}
vec3 p = pos.xyz;
vec3 n = normalize(imageLoad(g_normal, pixel_coords).xyz);
// integer material id
uint mid = imageLoad(g_material_id, pixel_coords).r;
hit.hit = true;
hit.position = p;
hit.normal = n;
hit.material_id = mid;
// For RR/any debug usage; path tracing uses this as starting point only.
hit.t = length(p - ray.origin);
return hit;
}
// ============================================================================ // ============================================================================
// Material + scattering // Material + scattering
// ============================================================================ // ============================================================================
@ -429,7 +460,6 @@ ScatterResult scatter_ray(Ray ray_in, HitInfo hit, Material mat, inout uint seed
vec3 eval_direct_lighting(HitInfo hit, Material mat, inout uint seed) { vec3 eval_direct_lighting(HitInfo hit, Material mat, inout uint seed) {
if (u_light_count == 0u) return vec3(0.0); if (u_light_count == 0u) return vec3(0.0);
// sample one light
uint light_idx = uint(random_float(seed) * float(u_light_count)) % u_light_count; uint light_idx = uint(random_float(seed) * float(u_light_count)) % u_light_count;
Light light = lights[light_idx]; Light light = lights[light_idx];
@ -455,18 +485,15 @@ vec3 eval_direct_lighting(HitInfo hit, Material mat, inout uint seed) {
float n_dot_l = max(dot(hit.normal, L), 0.0); float n_dot_l = max(dot(hit.normal, L), 0.0);
if (n_dot_l <= 0.0) return vec3(0.0); if (n_dot_l <= 0.0) return vec3(0.0);
// shadow ray
Ray shadow_ray; Ray shadow_ray;
shadow_ray.origin = hit.position + hit.normal * EPSILON; shadow_ray.origin = hit.position + hit.normal * EPSILON;
shadow_ray.direction = L; shadow_ray.direction = L;
float t_max = (light.type == LIGHT_POINT) ? (dist - EPSILON) : MAX_FLOAT; float t_max = (light.type == LIGHT_POINT) ? (dist - EPSILON) : MAX_FLOAT;
if (trace_any_bvh(shadow_ray, t_max)) { if (trace_any_bvh(shadow_ray, t_max)) return vec3(0.0);
return vec3(0.0);
}
float pdf_light = 1.0 / float(u_light_count); float pdf_light = 1.0 / float(u_light_count);
vec3 brdf = mat.albedo * INV_PI; // diffuse direct only (simple) vec3 brdf = mat.albedo * INV_PI;
return brdf * radiance * n_dot_l / max(pdf_light, EPSILON); return brdf * radiance * n_dot_l / max(pdf_light, EPSILON);
} }
@ -489,15 +516,52 @@ Material fetch_material(uint material_id) {
} }
vec3 environment_color(vec3 dir) { vec3 environment_color(vec3 dir) {
// simple dark sky
return vec3(0.1, 0.1, 0.15); return vec3(0.1, 0.1, 0.15);
} }
vec3 trace_path(Ray ray, inout uint seed) { Ray generate_camera_ray_center(ivec2 pixel_coords, ivec2 image_size) {
vec2 uv = (vec2(pixel_coords) + vec2(0.5)) / vec2(image_size);
vec2 ndc = uv * 2.0 - 1.0;
vec4 p_near = u_inv_view_projection * vec4(ndc, 0.0, 1.0);
vec4 p_far = u_inv_view_projection * vec4(ndc, 1.0, 1.0);
vec3 near_ws = p_near.xyz / p_near.w;
vec3 far_ws = p_far.xyz / p_far.w;
Ray r;
r.origin = near_ws;
r.direction = normalize(far_ws - near_ws);
return r;
}
/**
* @brief Trace path with primary-ray G-Buffer acceleration
*/
vec3 trace_path_primary_gbuffer(ivec2 pixel_coords, ivec2 image_size, inout uint seed) {
Ray ray = generate_camera_ray_center(pixel_coords, image_size);
vec3 radiance = vec3(0.0); vec3 radiance = vec3(0.0);
vec3 throughput = vec3(1.0); vec3 throughput = vec3(1.0);
for (uint depth = 0u; depth < u_max_depth; ++depth) { // Depth 0: try G-Buffer hit first
HitInfo hit0 = trace_primary_gbuffer(ray, pixel_coords);
if (hit0.hit) {
Material mat0 = fetch_material(hit0.material_id);
radiance += throughput * mat0.emission;
if (mat0.type == MATERIAL_DIFFUSE) {
radiance += throughput * eval_direct_lighting(hit0, mat0, seed);
}
ScatterResult sc0 = scatter_ray(ray, hit0, mat0, seed);
if (!sc0.scattered) return radiance;
throughput *= sc0.attenuation;
ray = sc0.scattered_ray;
}
// Subsequent bounces: BVH
for (uint depth = (hit0.hit ? 1u : 0u); depth < u_max_depth; ++depth) {
HitInfo hit = trace_ray_bvh(ray); HitInfo hit = trace_ray_bvh(ray);
if (!hit.hit) { if (!hit.hit) {
radiance += throughput * environment_color(ray.direction); radiance += throughput * environment_color(ray.direction);
@ -506,10 +570,7 @@ vec3 trace_path(Ray ray, inout uint seed) {
Material mat = fetch_material(hit.material_id); Material mat = fetch_material(hit.material_id);
// emission
radiance += throughput * mat.emission; radiance += throughput * mat.emission;
// direct light (only for diffuse to keep simple)
if (mat.type == MATERIAL_DIFFUSE) { if (mat.type == MATERIAL_DIFFUSE) {
radiance += throughput * eval_direct_lighting(hit, mat, seed); radiance += throughput * eval_direct_lighting(hit, mat, seed);
} }
@ -519,7 +580,6 @@ vec3 trace_path(Ray ray, inout uint seed) {
throughput *= sc.attenuation; throughput *= sc.attenuation;
// RR
if (depth > 3u) { if (depth > 3u) {
float p = max(throughput.r, max(throughput.g, throughput.b)); float p = max(throughput.r, max(throughput.g, throughput.b));
p = clamp(p, 0.0, 0.95); p = clamp(p, 0.0, 0.95);
@ -544,12 +604,10 @@ void main() {
uint seed = base_seed + u_frame_count * 719393u; uint seed = base_seed + u_frame_count * 719393u;
vec3 color = vec3(0.0); vec3 color = vec3(0.0);
// Multi-sample
uint spp = max(u_samples_per_pixel, 1u); uint spp = max(u_samples_per_pixel, 1u);
for (uint s = 0u; s < spp; ++s) { for (uint s = 0u; s < spp; ++s) {
Ray cam_ray = generate_camera_ray(pixel_coords, image_size, seed); color += trace_path_primary_gbuffer(pixel_coords, image_size, seed);
color += trace_path(cam_ray, seed);
} }
color /= float(spp); color /= float(spp);

View File

@ -135,6 +135,11 @@ void BVH::build_recursive_(uint node_idx, uint first_prim, uint prim_count) {
int axis; int axis;
float split_pos; float split_pos;
float split_cost = find_best_split_(first_prim, prim_count, axis, split_pos); float split_cost = find_best_split_(first_prim, prim_count, axis, split_pos);
if(split_cost == std::numeric_limits<float>::max()) {
node.left_first_ = first_prim;
node.count_ = prim_count;
return;
}
// Check if split is beneficial // Check if split is beneficial
float no_split_cost = prim_count * bounds.surface_area(); float no_split_cost = prim_count * bounds.surface_area();
@ -180,6 +185,7 @@ void BVH::build_recursive_(uint node_idx, uint first_prim, uint prim_count) {
float BVH::find_best_split_(uint first_prim, uint prim_count, int& axis, float& split_pos) { float BVH::find_best_split_(uint first_prim, uint prim_count, int& axis, float& split_pos) {
float best_cost = std::numeric_limits<float>::max(); float best_cost = std::numeric_limits<float>::max();
axis = 0, split_pos = 0.0f;
AABB centroid_bounds = calculate_centroid_bounds_(first_prim, prim_count); AABB centroid_bounds = calculate_centroid_bounds_(first_prim, prim_count);

View File

@ -1,6 +1,6 @@
#include "core/raytracer.h" #include "core/raytracer.h"
#include "utils/logger.h"
#include "basic/constants.h" #include "basic/constants.h"
#include "utils/logger.h"
#include <glad/glad.h> #include <glad/glad.h>
namespace are { namespace are {
@ -42,14 +42,6 @@ bool RayTracer::initialize() {
glGenBuffers(1, &material_buffer_); glGenBuffers(1, &material_buffer_);
glGenBuffers(1, &light_buffer_); glGenBuffers(1, &light_buffer_);
// Load compute shader
Logger::info("Loading ray tracing compute shader in RayTracer...");
if (!compute_shader_.load_compute("shaders/raytracing.comp")) {
Logger::error("Failed to load ray tracing compute shader in RayTracer");
return false;
}
Logger::info("Ray tracing compute shader loaded in RayTracer");
// Initialize BVH if enabled // Initialize BVH if enabled
if (config_.use_bvh_) { if (config_.use_bvh_) {
bvh_ = std::make_unique<BVH>(); bvh_ = std::make_unique<BVH>();
@ -61,7 +53,8 @@ bool RayTracer::initialize() {
} }
void RayTracer::release() { void RayTracer::release() {
if (!initialized_) return; if (!initialized_)
return;
if (accumulation_texture_ != INVALID_HANDLE) { if (accumulation_texture_ != INVALID_HANDLE) {
glDeleteTextures(1, &accumulation_texture_); glDeleteTextures(1, &accumulation_texture_);
@ -81,8 +74,6 @@ void RayTracer::release() {
bvh_node_buffer_.release(); bvh_node_buffer_.release();
bvh_triangle_buffer_.release(); bvh_triangle_buffer_.release();
compute_shader_.release();
bvh_.reset(); bvh_.reset();
bvh_built_ = false; bvh_built_ = false;
@ -123,7 +114,7 @@ void RayTracer::trace(const Scene& scene, const GBuffer& gbuffer, TextureHandle
return; return;
} }
if (!compute_shader_.is_valid()) { if (!compute_shader_->is_valid()) {
Logger::error("Ray tracing compute shader not loaded"); Logger::error("Ray tracing compute shader not loaded");
return; return;
} }
@ -137,7 +128,11 @@ void RayTracer::trace(const Scene& scene, const GBuffer& gbuffer, TextureHandle
upload_scene_data_(scene); upload_scene_data_(scene);
// Use compute shader // Use compute shader
compute_shader_.use(); if (!compute_shader_ || !compute_shader_->is_valid()) {
Logger::error("Ray tracing compute shader not set or invalid");
return;
}
compute_shader_->use();
// Bind G-Buffer textures // Bind G-Buffer textures
bind_gbuffer_(gbuffer); bind_gbuffer_(gbuffer);
@ -150,25 +145,25 @@ void RayTracer::trace(const Scene& scene, const GBuffer& gbuffer, TextureHandle
if (config_.use_bvh_ && bvh_built_) { if (config_.use_bvh_ && bvh_built_) {
bvh_node_buffer_.bind_base(2); bvh_node_buffer_.bind_base(2);
bvh_triangle_buffer_.bind_base(3); bvh_triangle_buffer_.bind_base(3);
compute_shader_.set_bool("u_use_bvh", true); compute_shader_->set_bool("u_use_bvh", true);
compute_shader_.set_uint("u_bvh_node_count", bvh_->get_node_count()); compute_shader_->set_uint("u_bvh_node_count", bvh_->get_node_count());
} else { } else {
compute_shader_.set_bool("u_use_bvh", false); compute_shader_->set_bool("u_use_bvh", false);
} }
// Set uniforms // Set uniforms
compute_shader_.set_uint("u_frame_count", frame_count_); 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_samples_per_pixel", config_.samples_per_pixel_);
compute_shader_.set_uint("u_max_depth", config_.max_depth_); compute_shader_->set_uint("u_max_depth", config_.max_depth_);
compute_shader_.set_uint("u_light_count", static_cast<uint>(scene.get_lights().size())); compute_shader_->set_uint("u_light_count", static_cast<uint>(scene.get_lights().size()));
compute_shader_.set_bool("u_enable_accumulation", config_.enable_accumulation_); compute_shader_->set_bool("u_enable_accumulation", config_.enable_accumulation_);
// Set camera data // Set camera data
const Camera &camera = scene.get_camera(); const Camera &camera = scene.get_camera();
compute_shader_.set_vec3("u_camera_position", camera.get_position()); compute_shader_->set_vec3("u_camera_position", camera.get_position());
Mat4 inv_vp = glm::inverse(camera.get_view_projection_matrix()); Mat4 inv_vp = glm::inverse(camera.get_view_projection_matrix());
compute_shader_.set_mat4("u_inv_view_projection", inv_vp); compute_shader_->set_mat4("u_inv_view_projection", inv_vp);
// Dispatch compute shader // Dispatch compute shader
uint num_groups_x = (width_ + COMPUTE_GROUP_SIZE_X - 1) / COMPUTE_GROUP_SIZE_X; uint num_groups_x = (width_ + COMPUTE_GROUP_SIZE_X - 1) / COMPUTE_GROUP_SIZE_X;
@ -186,7 +181,8 @@ void RayTracer::trace(const Scene& scene, const GBuffer& gbuffer, TextureHandle
} }
void RayTracer::resize(uint width, uint height) { void RayTracer::resize(uint width, uint height) {
if (width == width_ && height == height_) return; if (width == width_ && height == height_)
return;
width_ = width; width_ = width;
height_ = height; height_ = height;
@ -311,7 +307,7 @@ void RayTracer::bind_gbuffer_(const GBuffer& gbuffer) {
glBindImageTexture(6, gbuffer.get_texture(GBUFFER_MATERIAL_ID), 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI); glBindImageTexture(6, gbuffer.get_texture(GBUFFER_MATERIAL_ID), 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
} }
void RayTracer::set_compute_shader(const Shader& shader) { void RayTracer::set_compute_shader(const std::shared_ptr<Shader> &shader) {
compute_shader_ = shader; compute_shader_ = shader;
Logger::info("Compute shader set for RayTracer"); Logger::info("Compute shader set for RayTracer");
} }

View File

@ -53,8 +53,8 @@ bool Renderer::initialize() {
} }
// Pass compute shader to ray tracer // Pass compute shader to ray tracer
const Shader& rt_shader = shader_manager_->get_raytracing_shader(); const auto& rt_shader = shader_manager_->get_raytracing_shader();
if (!rt_shader.is_valid()) { if (!rt_shader || !rt_shader->is_valid()) {
Logger::error("Ray tracing shader is invalid"); Logger::error("Ray tracing shader is invalid");
return false; return false;
} }
@ -116,8 +116,12 @@ RenderStats Renderer::render(const Scene& scene, TextureHandle output_texture) {
// Phase 1: G-Buffer pass // Phase 1: G-Buffer pass
auto gbuffer_start = std::chrono::high_resolution_clock::now(); auto gbuffer_start = std::chrono::high_resolution_clock::now();
const Shader& gbuffer_shader = shader_manager_->get_gbuffer_shader(); const auto& gbuffer_shader = shader_manager_->get_gbuffer_shader();
gbuffer_->render(scene, gbuffer_shader); if (!gbuffer_shader || !gbuffer_shader->is_valid()) {
Logger::error("G-Buffer shader is invalid");
return stats;
}
gbuffer_->render(scene, *gbuffer_shader);
auto gbuffer_end = std::chrono::high_resolution_clock::now(); auto gbuffer_end = std::chrono::high_resolution_clock::now();
stats.gbuffer_time_ms_ = std::chrono::duration<float, std::milli>(gbuffer_end - gbuffer_start).count(); stats.gbuffer_time_ms_ = std::chrono::duration<float, std::milli>(gbuffer_end - gbuffer_start).count();
@ -202,4 +206,9 @@ void Renderer::set_config(const RendererConfig &config) {
} }
} }
void Renderer::notify_scene_changed(const Scene &scene) {
raytracer_->reset_accumulation();
raytracer_->rebuild_bvh(scene);
}
} // namespace are } // namespace are

View File

@ -32,33 +32,31 @@ bool ShaderManager::initialize() {
void ShaderManager::release() { void ShaderManager::release() {
if (!initialized_) return; if (!initialized_) return;
gbuffer_shader_.release();
raytracing_shader_.release();
for (auto& pair : shader_cache_) { for (auto& pair : shader_cache_) {
pair.second.release(); if (pair.second) pair.second->release();
} }
shader_cache_.clear(); shader_cache_.clear();
gbuffer_shader_.reset();
raytracing_shader_.reset();
initialized_ = false; initialized_ = false;
Logger::info("ShaderManager released"); Logger::info("ShaderManager released");
} }
Shader ShaderManager::load_shader(const std::string& name, std::shared_ptr<Shader> ShaderManager::load_shader(const std::string& name,
const std::string& vertex_path, const std::string& vertex_path,
const std::string& fragment_path) { const std::string& fragment_path) {
// Check cache
auto it = shader_cache_.find(name); auto it = shader_cache_.find(name);
if (it != shader_cache_.end()) { if (it != shader_cache_.end()) {
Logger::info("Shader '" + name + "' loaded from cache"); Logger::info("Shader '" + name + "' loaded from cache");
return it->second; return it->second;
} }
// Load shader auto shader = std::make_shared<Shader>();
Shader shader; if (!shader->load(vertex_path, fragment_path)) {
if (!shader.load(vertex_path, fragment_path)) {
Logger::error("Failed to load shader '" + name + "'"); Logger::error("Failed to load shader '" + name + "'");
return Shader(); return nullptr;
} }
shader_cache_[name] = shader; shader_cache_[name] = shader;
@ -66,20 +64,18 @@ Shader ShaderManager::load_shader(const std::string& name,
return shader; return shader;
} }
Shader ShaderManager::load_compute_shader(const std::string& name, std::shared_ptr<Shader> ShaderManager::load_compute_shader(const std::string& name,
const std::string& compute_path) { const std::string& compute_path) {
// Check cache
auto it = shader_cache_.find(name); auto it = shader_cache_.find(name);
if (it != shader_cache_.end()) { if (it != shader_cache_.end()) {
Logger::info("Compute shader '" + name + "' loaded from cache"); Logger::info("Compute shader '" + name + "' loaded from cache");
return it->second; return it->second;
} }
// Load shader auto shader = std::make_shared<Shader>();
Shader shader; if (!shader->load_compute(compute_path)) {
if (!shader.load_compute(compute_path)) {
Logger::error("Failed to load compute shader '" + name + "'"); Logger::error("Failed to load compute shader '" + name + "'");
return Shader(); return nullptr;
} }
shader_cache_[name] = shader; shader_cache_[name] = shader;
@ -87,27 +83,25 @@ Shader ShaderManager::load_compute_shader(const std::string& name,
return shader; return shader;
} }
Shader ShaderManager::get_shader(const std::string& name) const { std::shared_ptr<Shader> ShaderManager::get_shader(const std::string& name) const {
auto it = shader_cache_.find(name); auto it = shader_cache_.find(name);
if (it != shader_cache_.end()) { if (it != shader_cache_.end()) return it->second;
return it->second;
}
Logger::warning("Shader '" + name + "' not found in cache"); Logger::warning("Shader '" + name + "' not found in cache");
return Shader(); return nullptr;
} }
bool ShaderManager::load_builtin_shaders_() { bool ShaderManager::load_builtin_shaders_() {
// Load G-Buffer shader gbuffer_shader_ = std::make_shared<Shader>();
if (!gbuffer_shader_.load("shaders/gbuffer.vert", "shaders/gbuffer.frag")) { if (!gbuffer_shader_->load("shaders/gbuffer.vert", "shaders/gbuffer.frag")) {
Logger::error("Failed to load G-Buffer shader"); Logger::error("Failed to load G-Buffer shader");
return false; return false;
} }
shader_cache_["gbuffer"] = gbuffer_shader_; shader_cache_["gbuffer"] = gbuffer_shader_;
// Load ray tracing compute shader
Logger::info("Loading ray tracing compute shader..."); Logger::info("Loading ray tracing compute shader...");
if (!raytracing_shader_.load_compute("shaders/raytracing.comp")) { raytracing_shader_ = std::make_shared<Shader>();
if (!raytracing_shader_->load_compute("shaders/raytracing.comp")) {
Logger::error("Failed to load ray tracing shader"); Logger::error("Failed to load ray tracing shader");
return false; return false;
} }

View File

@ -11,10 +11,29 @@ Shader::Shader()
: handle_(INVALID_HANDLE) { : handle_(INVALID_HANDLE) {
} }
Shader::Shader(Shader&& other) noexcept
: handle_(other.handle_)
, uniform_cache_(std::move(other.uniform_cache_)) {
other.handle_ = INVALID_HANDLE;
other.uniform_cache_.clear();
}
Shader::~Shader() { Shader::~Shader() {
// Don't auto-release, let user control lifetime // Don't auto-release, let user control lifetime
} }
Shader& Shader::operator=(Shader&& other) noexcept {
if (this == &other) return *this;
release();
handle_ = other.handle_;
uniform_cache_ = std::move(other.uniform_cache_);
other.handle_ = INVALID_HANDLE;
other.uniform_cache_.clear();
return *this;
}
bool Shader::load(const std::string& vertex_path, const std::string& fragment_path) { bool Shader::load(const std::string& vertex_path, const std::string& fragment_path) {
std::string vertex_source = read_file_(vertex_path); std::string vertex_source = read_file_(vertex_path);
std::string fragment_source = read_file_(fragment_path); std::string fragment_source = read_file_(fragment_path);