Refractor&Add: 使用shared_ptr优化Shader管理、添加基于G-Buffer的光线追踪、添加场景重建API
parent
52c6ace2cd
commit
b8ae9808a8
Binary file not shown.
|
|
@ -442,7 +442,7 @@ int main() {
|
|||
RendererConfig config;
|
||||
config.width_ = WINDOW_WIDTH;
|
||||
config.height_ = WINDOW_HEIGHT;
|
||||
config.samples_per_pixel_ = 1;
|
||||
config.samples_per_pixel_ = 4;
|
||||
config.max_ray_depth_ = 4;
|
||||
config.enable_accumulation_ = false;
|
||||
config.enable_denoising_ = false;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "resource/buffer.h"
|
||||
#include "resource/shader.h"
|
||||
#include "scene/scene.h"
|
||||
#include <memory>
|
||||
|
||||
namespace are {
|
||||
|
||||
|
|
@ -70,14 +71,14 @@ public:
|
|||
|
||||
/// @brief Set compute shader (called by renderer)
|
||||
/// @param shader Compute shader
|
||||
void set_compute_shader(const Shader &shader);
|
||||
void set_compute_shader(const std::shared_ptr<Shader>& shader);
|
||||
|
||||
private:
|
||||
uint width_;
|
||||
uint height_;
|
||||
RayTracerConfig config_;
|
||||
|
||||
Shader compute_shader_;
|
||||
std::shared_ptr<Shader> compute_shader_;
|
||||
TextureHandle accumulation_texture_;
|
||||
BufferHandle scene_buffer_;
|
||||
BufferHandle material_buffer_;
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ public:
|
|||
/// @param config New configuration
|
||||
void set_config(const RendererConfig& config);
|
||||
|
||||
/// @brief Notify scene changed to rebuild acceleration
|
||||
void notify_scene_changed(const Scene &scene);
|
||||
|
||||
private:
|
||||
RendererConfig config_;
|
||||
std::unique_ptr<GBuffer> gbuffer_;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "resource/shader.h"
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace are {
|
||||
|
||||
|
|
@ -29,7 +30,7 @@ public:
|
|||
/// @param vertex_path Vertex shader file path
|
||||
/// @param fragment_path Fragment shader file path
|
||||
/// @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& fragment_path);
|
||||
|
||||
|
|
@ -37,26 +38,26 @@ public:
|
|||
/// @param name Shader name for caching
|
||||
/// @param compute_path Compute shader file path
|
||||
/// @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);
|
||||
|
||||
/// @brief Get cached shader by name
|
||||
/// @param name Shader name
|
||||
/// @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
|
||||
/// @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
|
||||
/// @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:
|
||||
std::unordered_map<std::string, Shader> shader_cache_;
|
||||
Shader gbuffer_shader_;
|
||||
Shader raytracing_shader_;
|
||||
std::unordered_map<std::string, std::shared_ptr<Shader>> shader_cache_;
|
||||
std::shared_ptr<Shader> gbuffer_shader_;
|
||||
std::shared_ptr<Shader> raytracing_shader_;
|
||||
|
||||
bool initialized_;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,12 @@ public:
|
|||
/// @brief Constructor
|
||||
Shader();
|
||||
|
||||
Shader(const Shader&) = delete;
|
||||
Shader& operator=(const Shader&) = delete;
|
||||
|
||||
Shader(Shader&& other) noexcept;
|
||||
Shader& operator=(Shader&& other) noexcept;
|
||||
|
||||
/// @brief Destructor
|
||||
~Shader();
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ layout(binding = 0, rgba32f) uniform readonly image2D g_position;
|
|||
layout(binding = 1, rgba32f) uniform readonly image2D g_normal;
|
||||
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 = 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_max_depth;
|
||||
uniform uint u_light_count;
|
||||
uniform vec3 u_camera_position;
|
||||
uniform mat4 u_inv_view_projection;
|
||||
uniform bool u_enable_accumulation;
|
||||
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;
|
||||
if (t < EPSILON || t >= hit.t) return false;
|
||||
|
||||
// Interpolate normal/uv
|
||||
float w = 1.0 - u - v;
|
||||
vec3 n0 = tri.n0.xyz;
|
||||
vec3 n1 = tri.n1.xyz;
|
||||
|
|
@ -265,7 +263,6 @@ HitInfo trace_ray_bvh(Ray ray) {
|
|||
return hit;
|
||||
}
|
||||
|
||||
// Small fixed stack
|
||||
uint stack[64];
|
||||
int sp = 0;
|
||||
stack[sp++] = 0u;
|
||||
|
|
@ -288,11 +285,8 @@ HitInfo trace_ray_bvh(Ray ray) {
|
|||
intersect_triangle(ray, tri, hit);
|
||||
}
|
||||
} else {
|
||||
// Interior: push children
|
||||
uint left = left_first;
|
||||
uint right = left_first + 1u;
|
||||
|
||||
// Depth-first; no sorting (simple)
|
||||
if (sp < 63) stack[sp++] = right;
|
||||
if (sp < 63) stack[sp++] = left;
|
||||
}
|
||||
|
|
@ -330,9 +324,7 @@ bool trace_any_bvh(Ray ray, float t_max) {
|
|||
if (count > 0u) {
|
||||
for (uint i = 0u; i < count; ++i) {
|
||||
TriangleGpu tri = bvh_tris[left_first + i];
|
||||
if (intersect_triangle(ray, tri, hit)) {
|
||||
return true;
|
||||
}
|
||||
if (intersect_triangle(ray, tri, hit)) return true;
|
||||
}
|
||||
} else {
|
||||
uint left = left_first;
|
||||
|
|
@ -345,6 +337,45 @@ bool trace_any_bvh(Ray ray, float t_max) {
|
|||
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
|
||||
// ============================================================================
|
||||
|
|
@ -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) {
|
||||
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;
|
||||
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);
|
||||
if (n_dot_l <= 0.0) return vec3(0.0);
|
||||
|
||||
// shadow ray
|
||||
Ray shadow_ray;
|
||||
shadow_ray.origin = hit.position + hit.normal * EPSILON;
|
||||
shadow_ray.direction = L;
|
||||
|
||||
float t_max = (light.type == LIGHT_POINT) ? (dist - EPSILON) : MAX_FLOAT;
|
||||
if (trace_any_bvh(shadow_ray, t_max)) {
|
||||
return vec3(0.0);
|
||||
}
|
||||
if (trace_any_bvh(shadow_ray, t_max)) return vec3(0.0);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -489,15 +516,52 @@ Material fetch_material(uint material_id) {
|
|||
}
|
||||
|
||||
vec3 environment_color(vec3 dir) {
|
||||
// simple dark sky
|
||||
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 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);
|
||||
if (!hit.hit) {
|
||||
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);
|
||||
|
||||
// emission
|
||||
radiance += throughput * mat.emission;
|
||||
|
||||
// direct light (only for diffuse to keep simple)
|
||||
if (mat.type == MATERIAL_DIFFUSE) {
|
||||
radiance += throughput * eval_direct_lighting(hit, mat, seed);
|
||||
}
|
||||
|
|
@ -519,7 +580,6 @@ vec3 trace_path(Ray ray, inout uint seed) {
|
|||
|
||||
throughput *= sc.attenuation;
|
||||
|
||||
// RR
|
||||
if (depth > 3u) {
|
||||
float p = max(throughput.r, max(throughput.g, throughput.b));
|
||||
p = clamp(p, 0.0, 0.95);
|
||||
|
|
@ -544,12 +604,10 @@ void main() {
|
|||
uint seed = base_seed + u_frame_count * 719393u;
|
||||
|
||||
vec3 color = vec3(0.0);
|
||||
|
||||
// Multi-sample
|
||||
uint spp = max(u_samples_per_pixel, 1u);
|
||||
|
||||
for (uint s = 0u; s < spp; ++s) {
|
||||
Ray cam_ray = generate_camera_ray(pixel_coords, image_size, seed);
|
||||
color += trace_path(cam_ray, seed);
|
||||
color += trace_path_primary_gbuffer(pixel_coords, image_size, seed);
|
||||
}
|
||||
color /= float(spp);
|
||||
|
||||
|
|
|
|||
|
|
@ -135,6 +135,11 @@ void BVH::build_recursive_(uint node_idx, uint first_prim, uint prim_count) {
|
|||
int axis;
|
||||
float 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
|
||||
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 best_cost = std::numeric_limits<float>::max();
|
||||
axis = 0, split_pos = 0.0f;
|
||||
|
||||
AABB centroid_bounds = calculate_centroid_bounds_(first_prim, prim_count);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
#include "core/raytracer.h"
|
||||
#include "utils/logger.h"
|
||||
#include "basic/constants.h"
|
||||
#include "utils/logger.h"
|
||||
#include <glad/glad.h>
|
||||
|
||||
namespace are {
|
||||
|
||||
RayTracer::RayTracer(uint width, uint height, const RayTracerConfig& config)
|
||||
RayTracer::RayTracer(uint width, uint height, const RayTracerConfig &config)
|
||||
: width_(width)
|
||||
, height_(height)
|
||||
, config_(config)
|
||||
|
|
@ -42,14 +42,6 @@ bool RayTracer::initialize() {
|
|||
glGenBuffers(1, &material_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
|
||||
if (config_.use_bvh_) {
|
||||
bvh_ = std::make_unique<BVH>();
|
||||
|
|
@ -61,7 +53,8 @@ bool RayTracer::initialize() {
|
|||
}
|
||||
|
||||
void RayTracer::release() {
|
||||
if (!initialized_) return;
|
||||
if (!initialized_)
|
||||
return;
|
||||
|
||||
if (accumulation_texture_ != INVALID_HANDLE) {
|
||||
glDeleteTextures(1, &accumulation_texture_);
|
||||
|
|
@ -81,8 +74,6 @@ void RayTracer::release() {
|
|||
bvh_node_buffer_.release();
|
||||
bvh_triangle_buffer_.release();
|
||||
|
||||
compute_shader_.release();
|
||||
|
||||
bvh_.reset();
|
||||
bvh_built_ = false;
|
||||
|
||||
|
|
@ -90,7 +81,7 @@ void RayTracer::release() {
|
|||
Logger::info("RayTracer released");
|
||||
}
|
||||
|
||||
bool RayTracer::rebuild_bvh(const Scene& scene) {
|
||||
bool RayTracer::rebuild_bvh(const Scene &scene) {
|
||||
if (!config_.use_bvh_) {
|
||||
Logger::warning("BVH is disabled in configuration");
|
||||
return false;
|
||||
|
|
@ -117,13 +108,13 @@ bool RayTracer::rebuild_bvh(const Scene& scene) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void RayTracer::trace(const Scene& scene, const GBuffer& gbuffer, TextureHandle output_texture) {
|
||||
void RayTracer::trace(const Scene &scene, const GBuffer &gbuffer, TextureHandle output_texture) {
|
||||
if (!initialized_) {
|
||||
Logger::error("RayTracer not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!compute_shader_.is_valid()) {
|
||||
if (!compute_shader_->is_valid()) {
|
||||
Logger::error("Ray tracing compute shader not loaded");
|
||||
return;
|
||||
}
|
||||
|
|
@ -137,7 +128,11 @@ void RayTracer::trace(const Scene& scene, const GBuffer& gbuffer, TextureHandle
|
|||
upload_scene_data_(scene);
|
||||
|
||||
// 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_gbuffer_(gbuffer);
|
||||
|
|
@ -150,25 +145,25 @@ void RayTracer::trace(const Scene& scene, const GBuffer& gbuffer, TextureHandle
|
|||
if (config_.use_bvh_ && bvh_built_) {
|
||||
bvh_node_buffer_.bind_base(2);
|
||||
bvh_triangle_buffer_.bind_base(3);
|
||||
compute_shader_.set_bool("u_use_bvh", true);
|
||||
compute_shader_.set_uint("u_bvh_node_count", bvh_->get_node_count());
|
||||
compute_shader_->set_bool("u_use_bvh", true);
|
||||
compute_shader_->set_uint("u_bvh_node_count", bvh_->get_node_count());
|
||||
} else {
|
||||
compute_shader_.set_bool("u_use_bvh", false);
|
||||
compute_shader_->set_bool("u_use_bvh", false);
|
||||
}
|
||||
|
||||
// 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_light_count", static_cast<uint>(scene.get_lights().size()));
|
||||
compute_shader_.set_bool("u_enable_accumulation", config_.enable_accumulation_);
|
||||
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_light_count", static_cast<uint>(scene.get_lights().size()));
|
||||
compute_shader_->set_bool("u_enable_accumulation", config_.enable_accumulation_);
|
||||
|
||||
// Set camera data
|
||||
const Camera& camera = scene.get_camera();
|
||||
compute_shader_.set_vec3("u_camera_position", camera.get_position());
|
||||
const Camera &camera = scene.get_camera();
|
||||
compute_shader_->set_vec3("u_camera_position", camera.get_position());
|
||||
|
||||
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
|
||||
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) {
|
||||
if (width == width_ && height == height_) return;
|
||||
if (width == width_ && height == height_)
|
||||
return;
|
||||
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
|
|
@ -213,7 +209,7 @@ void RayTracer::reset_accumulation() {
|
|||
frame_count_ = 0;
|
||||
}
|
||||
|
||||
void RayTracer::set_config(const RayTracerConfig& config) {
|
||||
void RayTracer::set_config(const RayTracerConfig &config) {
|
||||
bool bvh_changed = (config.use_bvh_ != config_.use_bvh_);
|
||||
|
||||
config_ = config;
|
||||
|
|
@ -230,9 +226,9 @@ void RayTracer::set_config(const RayTracerConfig& config) {
|
|||
}
|
||||
}
|
||||
|
||||
void RayTracer::upload_scene_data_(const Scene& scene) {
|
||||
void RayTracer::upload_scene_data_(const Scene &scene) {
|
||||
// Upload materials
|
||||
const auto& materials = scene.get_materials();
|
||||
const auto &materials = scene.get_materials();
|
||||
if (!materials.empty()) {
|
||||
struct MaterialData {
|
||||
Vec3 albedo;
|
||||
|
|
@ -247,7 +243,7 @@ void RayTracer::upload_scene_data_(const Scene& scene) {
|
|||
std::vector<MaterialData> material_data;
|
||||
material_data.reserve(materials.size());
|
||||
|
||||
for (const auto& mat : materials) {
|
||||
for (const auto &mat : materials) {
|
||||
MaterialData data;
|
||||
data.albedo = mat->get_albedo();
|
||||
data.metallic = mat->get_metallic();
|
||||
|
|
@ -266,7 +262,7 @@ void RayTracer::upload_scene_data_(const Scene& scene) {
|
|||
}
|
||||
|
||||
// Upload lights
|
||||
const auto& lights = scene.get_lights();
|
||||
const auto &lights = scene.get_lights();
|
||||
if (!lights.empty()) {
|
||||
struct LightData {
|
||||
Vec3 position;
|
||||
|
|
@ -282,7 +278,7 @@ void RayTracer::upload_scene_data_(const Scene& scene) {
|
|||
std::vector<LightData> light_data;
|
||||
light_data.reserve(lights.size());
|
||||
|
||||
for (const auto& light : lights) {
|
||||
for (const auto &light : lights) {
|
||||
LightData data;
|
||||
data.position = light->get_position();
|
||||
data.type = static_cast<int>(light->get_type());
|
||||
|
|
@ -302,7 +298,7 @@ void RayTracer::upload_scene_data_(const Scene& scene) {
|
|||
}
|
||||
}
|
||||
|
||||
void RayTracer::bind_gbuffer_(const GBuffer& gbuffer) {
|
||||
void RayTracer::bind_gbuffer_(const GBuffer &gbuffer) {
|
||||
glBindImageTexture(0, gbuffer.get_texture(GBUFFER_POSITION), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
|
||||
glBindImageTexture(1, gbuffer.get_texture(GBUFFER_NORMAL), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
|
||||
glBindImageTexture(2, gbuffer.get_texture(GBUFFER_ALBEDO), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
void RayTracer::set_compute_shader(const Shader& shader) {
|
||||
void RayTracer::set_compute_shader(const std::shared_ptr<Shader> &shader) {
|
||||
compute_shader_ = shader;
|
||||
Logger::info("Compute shader set for RayTracer");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ bool Renderer::initialize() {
|
|||
}
|
||||
|
||||
// Pass compute shader to ray tracer
|
||||
const Shader& rt_shader = shader_manager_->get_raytracing_shader();
|
||||
if (!rt_shader.is_valid()) {
|
||||
const auto& rt_shader = shader_manager_->get_raytracing_shader();
|
||||
if (!rt_shader || !rt_shader->is_valid()) {
|
||||
Logger::error("Ray tracing shader is invalid");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -116,8 +116,12 @@ RenderStats Renderer::render(const Scene& scene, TextureHandle output_texture) {
|
|||
// Phase 1: G-Buffer pass
|
||||
auto gbuffer_start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
const Shader& gbuffer_shader = shader_manager_->get_gbuffer_shader();
|
||||
gbuffer_->render(scene, gbuffer_shader);
|
||||
const auto& gbuffer_shader = shader_manager_->get_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();
|
||||
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
|
||||
|
|
|
|||
|
|
@ -32,33 +32,31 @@ bool ShaderManager::initialize() {
|
|||
void ShaderManager::release() {
|
||||
if (!initialized_) return;
|
||||
|
||||
gbuffer_shader_.release();
|
||||
raytracing_shader_.release();
|
||||
|
||||
for (auto& pair : shader_cache_) {
|
||||
pair.second.release();
|
||||
if (pair.second) pair.second->release();
|
||||
}
|
||||
shader_cache_.clear();
|
||||
|
||||
gbuffer_shader_.reset();
|
||||
raytracing_shader_.reset();
|
||||
|
||||
initialized_ = false;
|
||||
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& fragment_path) {
|
||||
// Check cache
|
||||
auto it = shader_cache_.find(name);
|
||||
if (it != shader_cache_.end()) {
|
||||
Logger::info("Shader '" + name + "' loaded from cache");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Load shader
|
||||
Shader shader;
|
||||
if (!shader.load(vertex_path, fragment_path)) {
|
||||
auto shader = std::make_shared<Shader>();
|
||||
if (!shader->load(vertex_path, fragment_path)) {
|
||||
Logger::error("Failed to load shader '" + name + "'");
|
||||
return Shader();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
shader_cache_[name] = shader;
|
||||
|
|
@ -66,20 +64,18 @@ Shader ShaderManager::load_shader(const std::string& name,
|
|||
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) {
|
||||
// Check cache
|
||||
auto it = shader_cache_.find(name);
|
||||
if (it != shader_cache_.end()) {
|
||||
Logger::info("Compute shader '" + name + "' loaded from cache");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Load shader
|
||||
Shader shader;
|
||||
if (!shader.load_compute(compute_path)) {
|
||||
auto shader = std::make_shared<Shader>();
|
||||
if (!shader->load_compute(compute_path)) {
|
||||
Logger::error("Failed to load compute shader '" + name + "'");
|
||||
return Shader();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
shader_cache_[name] = shader;
|
||||
|
|
@ -87,27 +83,25 @@ Shader ShaderManager::load_compute_shader(const std::string& name,
|
|||
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);
|
||||
if (it != shader_cache_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
if (it != shader_cache_.end()) return it->second;
|
||||
|
||||
Logger::warning("Shader '" + name + "' not found in cache");
|
||||
return Shader();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ShaderManager::load_builtin_shaders_() {
|
||||
// Load G-Buffer shader
|
||||
if (!gbuffer_shader_.load("shaders/gbuffer.vert", "shaders/gbuffer.frag")) {
|
||||
gbuffer_shader_ = std::make_shared<Shader>();
|
||||
if (!gbuffer_shader_->load("shaders/gbuffer.vert", "shaders/gbuffer.frag")) {
|
||||
Logger::error("Failed to load G-Buffer shader");
|
||||
return false;
|
||||
}
|
||||
shader_cache_["gbuffer"] = gbuffer_shader_;
|
||||
|
||||
// Load 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");
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,29 @@ Shader::Shader()
|
|||
: 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() {
|
||||
// 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) {
|
||||
std::string vertex_source = read_file_(vertex_path);
|
||||
std::string fragment_source = read_file_(fragment_path);
|
||||
|
|
|
|||
Loading…
Reference in New Issue