Refractor&Add: 使用shared_ptr优化Shader管理、添加基于G-Buffer的光线追踪、添加场景重建API
parent
52c6ace2cd
commit
b8ae9808a8
Binary file not shown.
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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_;
|
||||||
|
|
|
||||||
|
|
@ -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_;
|
||||||
|
|
|
||||||
|
|
@ -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_;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
#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 {
|
||||||
|
|
||||||
RayTracer::RayTracer(uint width, uint height, const RayTracerConfig& config)
|
RayTracer::RayTracer(uint width, uint height, const RayTracerConfig &config)
|
||||||
: width_(width)
|
: width_(width)
|
||||||
, height_(height)
|
, height_(height)
|
||||||
, config_(config)
|
, config_(config)
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
@ -90,7 +81,7 @@ void RayTracer::release() {
|
||||||
Logger::info("RayTracer released");
|
Logger::info("RayTracer released");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RayTracer::rebuild_bvh(const Scene& scene) {
|
bool RayTracer::rebuild_bvh(const Scene &scene) {
|
||||||
if (!config_.use_bvh_) {
|
if (!config_.use_bvh_) {
|
||||||
Logger::warning("BVH is disabled in configuration");
|
Logger::warning("BVH is disabled in configuration");
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -117,13 +108,13 @@ bool RayTracer::rebuild_bvh(const Scene& scene) {
|
||||||
return true;
|
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_) {
|
if (!initialized_) {
|
||||||
Logger::error("RayTracer not initialized");
|
Logger::error("RayTracer not initialized");
|
||||||
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;
|
||||||
|
|
@ -213,7 +209,7 @@ void RayTracer::reset_accumulation() {
|
||||||
frame_count_ = 0;
|
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_);
|
bool bvh_changed = (config.use_bvh_ != config_.use_bvh_);
|
||||||
|
|
||||||
config_ = config;
|
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
|
// Upload materials
|
||||||
const auto& materials = scene.get_materials();
|
const auto &materials = scene.get_materials();
|
||||||
if (!materials.empty()) {
|
if (!materials.empty()) {
|
||||||
struct MaterialData {
|
struct MaterialData {
|
||||||
Vec3 albedo;
|
Vec3 albedo;
|
||||||
|
|
@ -247,7 +243,7 @@ void RayTracer::upload_scene_data_(const Scene& scene) {
|
||||||
std::vector<MaterialData> material_data;
|
std::vector<MaterialData> material_data;
|
||||||
material_data.reserve(materials.size());
|
material_data.reserve(materials.size());
|
||||||
|
|
||||||
for (const auto& mat : materials) {
|
for (const auto &mat : materials) {
|
||||||
MaterialData data;
|
MaterialData data;
|
||||||
data.albedo = mat->get_albedo();
|
data.albedo = mat->get_albedo();
|
||||||
data.metallic = mat->get_metallic();
|
data.metallic = mat->get_metallic();
|
||||||
|
|
@ -266,7 +262,7 @@ void RayTracer::upload_scene_data_(const Scene& scene) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload lights
|
// Upload lights
|
||||||
const auto& lights = scene.get_lights();
|
const auto &lights = scene.get_lights();
|
||||||
if (!lights.empty()) {
|
if (!lights.empty()) {
|
||||||
struct LightData {
|
struct LightData {
|
||||||
Vec3 position;
|
Vec3 position;
|
||||||
|
|
@ -282,7 +278,7 @@ void RayTracer::upload_scene_data_(const Scene& scene) {
|
||||||
std::vector<LightData> light_data;
|
std::vector<LightData> light_data;
|
||||||
light_data.reserve(lights.size());
|
light_data.reserve(lights.size());
|
||||||
|
|
||||||
for (const auto& light : lights) {
|
for (const auto &light : lights) {
|
||||||
LightData data;
|
LightData data;
|
||||||
data.position = light->get_position();
|
data.position = light->get_position();
|
||||||
data.type = static_cast<int>(light->get_type());
|
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(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(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);
|
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);
|
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");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue