feat:添加降噪模块(均值滤波)
parent
ee7c843845
commit
6b6c754b5f
Binary file not shown.
|
|
@ -445,7 +445,7 @@ int main() {
|
||||||
config.samples_per_pixel_ = 1;
|
config.samples_per_pixel_ = 1;
|
||||||
config.max_ray_depth_ = 4;
|
config.max_ray_depth_ = 4;
|
||||||
config.enable_accumulation_ = true;
|
config.enable_accumulation_ = true;
|
||||||
config.enable_denoising_ = false;
|
config.enable_denoising_ = true;
|
||||||
|
|
||||||
g_renderer = std::make_unique<Renderer>(config);
|
g_renderer = std::make_unique<Renderer>(config);
|
||||||
if (!g_renderer->initialize()) {
|
if (!g_renderer->initialize()) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
#ifndef ARE_INCLUDE_CORE_DENOISER_H
|
||||||
|
#define ARE_INCLUDE_CORE_DENOISER_H
|
||||||
|
|
||||||
|
#include "basic/types.h"
|
||||||
|
#include "resource/shader.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace are {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mean filter denoiser using compute shader
|
||||||
|
*/
|
||||||
|
class Denoiser {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct denoiser
|
||||||
|
* @param width Output width
|
||||||
|
* @param height Output height
|
||||||
|
*/
|
||||||
|
Denoiser(uint width, uint height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy denoiser
|
||||||
|
*/
|
||||||
|
~Denoiser();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize GPU resources
|
||||||
|
* @param shader Denoise compute shader (managed by ShaderManager)
|
||||||
|
* @return True on success
|
||||||
|
*/
|
||||||
|
bool initialize(const std::shared_ptr<Shader>& shader);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Release GPU resources
|
||||||
|
*/
|
||||||
|
void release();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resize internal targets
|
||||||
|
* @param width New width
|
||||||
|
* @param height New height
|
||||||
|
*/
|
||||||
|
void resize(uint width, uint height);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Apply mean filter
|
||||||
|
* @param input_texture RGBA32F input texture
|
||||||
|
* @param radius Filter radius (1 => 3x3)
|
||||||
|
* @return Output texture handle (internal)
|
||||||
|
*/
|
||||||
|
TextureHandle denoise(TextureHandle input_texture, int radius);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint width_;
|
||||||
|
uint height_;
|
||||||
|
std::shared_ptr<Shader> shader_;
|
||||||
|
TextureHandle output_texture_;
|
||||||
|
bool initialized_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create output texture
|
||||||
|
*/
|
||||||
|
void create_output_texture_();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace are
|
||||||
|
|
||||||
|
#endif // ARE_INCLUDE_CORE_DENOISER_H
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include "core/gbuffer.h"
|
#include "core/gbuffer.h"
|
||||||
#include "core/raytracer.h"
|
#include "core/raytracer.h"
|
||||||
#include "core/screen_blit.h"
|
#include "core/screen_blit.h"
|
||||||
|
#include "core/denoiser.h"
|
||||||
#include "core/shader_manager.h"
|
#include "core/shader_manager.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
@ -66,6 +67,7 @@ private:
|
||||||
std::unique_ptr<RayTracer> raytracer_;
|
std::unique_ptr<RayTracer> raytracer_;
|
||||||
std::unique_ptr<ShaderManager> shader_manager_;
|
std::unique_ptr<ShaderManager> shader_manager_;
|
||||||
std::unique_ptr<ScreenBlit> screen_blit_;
|
std::unique_ptr<ScreenBlit> screen_blit_;
|
||||||
|
std::unique_ptr<Denoiser> denoiser_;
|
||||||
|
|
||||||
bool initialized_;
|
bool initialized_;
|
||||||
uint frame_count_;
|
uint frame_count_;
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,15 @@ public:
|
||||||
/// @return Ray tracing shader
|
/// @return Ray tracing shader
|
||||||
const std::shared_ptr<Shader>& get_raytracing_shader() const { return raytracing_shader_; }
|
const std::shared_ptr<Shader>& get_raytracing_shader() const { return raytracing_shader_; }
|
||||||
|
|
||||||
|
/// @brief Get mean denoise compute shader
|
||||||
|
/// @return Denoise shader (nullptr if not loaded)
|
||||||
|
const std::shared_ptr<Shader>& get_denoise_shader() const { return denoise_shader_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<std::string, std::shared_ptr<Shader>> shader_cache_;
|
std::unordered_map<std::string, std::shared_ptr<Shader>> shader_cache_;
|
||||||
std::shared_ptr<Shader> gbuffer_shader_;
|
std::shared_ptr<Shader> gbuffer_shader_;
|
||||||
std::shared_ptr<Shader> raytracing_shader_;
|
std::shared_ptr<Shader> raytracing_shader_;
|
||||||
|
std::shared_ptr<Shader> denoise_shader_;
|
||||||
|
|
||||||
bool initialized_;
|
bool initialized_;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#version 430 core
|
||||||
|
|
||||||
|
layout(local_size_x = 16, local_size_y = 16) in;
|
||||||
|
|
||||||
|
layout(binding = 0, rgba32f) uniform readonly image2D u_input;
|
||||||
|
layout(binding = 1, rgba32f) uniform writeonly image2D u_output;
|
||||||
|
|
||||||
|
uniform int u_radius; // 1 => 3x3, 2 => 5x5
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
ivec2 p = ivec2(gl_GlobalInvocationID.xy);
|
||||||
|
ivec2 size = imageSize(u_output);
|
||||||
|
if (p.x >= size.x || p.y >= size.y) return;
|
||||||
|
|
||||||
|
vec3 sum = vec3(0.0);
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (int dy = -u_radius; dy <= u_radius; ++dy) {
|
||||||
|
for (int dx = -u_radius; dx <= u_radius; ++dx) {
|
||||||
|
ivec2 q = clamp(p + ivec2(dx, dy), ivec2(0), size - ivec2(1));
|
||||||
|
sum += imageLoad(u_input, q).rgb;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 out_color = sum / float(count);
|
||||||
|
imageStore(u_output, p, vec4(out_color, 1.0));
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
#include "core/denoiser.h"
|
||||||
|
#include "basic/constants.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
namespace are {
|
||||||
|
|
||||||
|
Denoiser::Denoiser(uint width, uint height)
|
||||||
|
: width_(width)
|
||||||
|
, height_(height)
|
||||||
|
, output_texture_(INVALID_HANDLE)
|
||||||
|
, initialized_(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Denoiser::~Denoiser() {
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Denoiser::initialize(const std::shared_ptr<Shader>& shader) {
|
||||||
|
if (initialized_) return true;
|
||||||
|
|
||||||
|
if (!shader || !shader->is_valid()) {
|
||||||
|
Logger::error("Invalid denoise shader");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
shader_ = shader;
|
||||||
|
create_output_texture_();
|
||||||
|
|
||||||
|
initialized_ = true;
|
||||||
|
Logger::info("Denoiser initialized");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Denoiser::release() {
|
||||||
|
if (!initialized_) return;
|
||||||
|
|
||||||
|
shader_.reset();
|
||||||
|
|
||||||
|
if (output_texture_ != INVALID_HANDLE) {
|
||||||
|
glDeleteTextures(1, &output_texture_);
|
||||||
|
output_texture_ = INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
initialized_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Denoiser::resize(uint width, uint height) {
|
||||||
|
if (width == width_ && height == height_) return;
|
||||||
|
width_ = width;
|
||||||
|
height_ = height;
|
||||||
|
|
||||||
|
if (!initialized_) return;
|
||||||
|
|
||||||
|
if (output_texture_ != INVALID_HANDLE) {
|
||||||
|
glDeleteTextures(1, &output_texture_);
|
||||||
|
output_texture_ = INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
create_output_texture_();
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureHandle Denoiser::denoise(TextureHandle input_texture, int radius) {
|
||||||
|
if (!initialized_) return input_texture;
|
||||||
|
|
||||||
|
radius = (radius < 0) ? 0 : radius;
|
||||||
|
|
||||||
|
shader_->use();
|
||||||
|
|
||||||
|
glBindImageTexture(0, input_texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
|
||||||
|
glBindImageTexture(1, output_texture_, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
|
||||||
|
|
||||||
|
shader_->set_int("u_radius", radius);
|
||||||
|
|
||||||
|
uint groups_x = (width_ + COMPUTE_GROUP_SIZE_X - 1) / COMPUTE_GROUP_SIZE_X;
|
||||||
|
uint groups_y = (height_ + COMPUTE_GROUP_SIZE_Y - 1) / COMPUTE_GROUP_SIZE_Y;
|
||||||
|
glDispatchCompute(groups_x, groups_y, 1);
|
||||||
|
|
||||||
|
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
|
||||||
|
|
||||||
|
return output_texture_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Denoiser::create_output_texture_() {
|
||||||
|
glGenTextures(1, &output_texture_);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, output_texture_);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width_, height_, 0, GL_RGBA, GL_FLOAT, nullptr);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace are
|
||||||
|
|
@ -66,6 +66,13 @@ bool Renderer::initialize() {
|
||||||
Logger::error("Failed to initialize screen blit");
|
Logger::error("Failed to initialize screen blit");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
denoiser_ = std::make_unique<Denoiser>(config_.width_, config_.height_);
|
||||||
|
const auto& denoise_shader = shader_manager_->get_denoise_shader();
|
||||||
|
if (!denoiser_->initialize(denoise_shader)) {
|
||||||
|
Logger::error("Failed to initialize denoiser");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
initialized_ = true;
|
initialized_ = true;
|
||||||
Logger::info("Aurora Rendering Engine initialized successfully");
|
Logger::info("Aurora Rendering Engine initialized successfully");
|
||||||
|
|
@ -98,6 +105,11 @@ void Renderer::shutdown() {
|
||||||
shader_manager_.reset();
|
shader_manager_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (denoiser_) {
|
||||||
|
denoiser_->release();
|
||||||
|
denoiser_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
initialized_ = false;
|
initialized_ = false;
|
||||||
Logger::info("Aurora Rendering Engine shut down");
|
Logger::info("Aurora Rendering Engine shut down");
|
||||||
}
|
}
|
||||||
|
|
@ -148,11 +160,18 @@ RenderStats Renderer::render(const Scene& scene, TextureHandle output_texture) {
|
||||||
auto raytrace_end = std::chrono::high_resolution_clock::now();
|
auto raytrace_end = std::chrono::high_resolution_clock::now();
|
||||||
stats.raytrace_time_ms_ = std::chrono::duration<float, std::milli>(raytrace_end - raytrace_start).count();
|
stats.raytrace_time_ms_ = std::chrono::duration<float, std::milli>(raytrace_end - raytrace_start).count();
|
||||||
|
|
||||||
// Phase 3: Blit to screen if output is default framebuffer
|
// Phase 3: Denoise texture
|
||||||
if (created_temp_texture && output_texture == 0) {
|
TextureHandle final_output = rt_output;
|
||||||
screen_blit_->blit_fullscreen(rt_output);
|
|
||||||
glDeleteTextures(1, &rt_output);
|
if (config_.enable_denoising_ && denoiser_) {
|
||||||
}
|
final_output = denoiser_->denoise(rt_output, 1); // radius=1 => 3x3 mean
|
||||||
|
}
|
||||||
|
|
||||||
|
// Phase 4: Blit to screen if output is default framebuffer
|
||||||
|
if (created_temp_texture && output_texture == 0) {
|
||||||
|
screen_blit_->blit_fullscreen(final_output);
|
||||||
|
glDeleteTextures(1, &rt_output);
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate total frame time
|
// Calculate total frame time
|
||||||
auto end_time = std::chrono::high_resolution_clock::now();
|
auto end_time = std::chrono::high_resolution_clock::now();
|
||||||
|
|
@ -182,6 +201,7 @@ void Renderer::resize(uint width, uint height) {
|
||||||
if (initialized_) {
|
if (initialized_) {
|
||||||
gbuffer_->resize(width, height);
|
gbuffer_->resize(width, height);
|
||||||
raytracer_->resize(width, height);
|
raytracer_->resize(width, height);
|
||||||
|
denoiser_->resize(width, height);
|
||||||
|
|
||||||
Logger::info("Renderer resized to " + std::to_string(width) + "x" + std::to_string(height));
|
Logger::info("Renderer resized to " + std::to_string(width) + "x" + std::to_string(height));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ void ShaderManager::release() {
|
||||||
|
|
||||||
gbuffer_shader_.reset();
|
gbuffer_shader_.reset();
|
||||||
raytracing_shader_.reset();
|
raytracing_shader_.reset();
|
||||||
|
denoise_shader_.reset();
|
||||||
|
|
||||||
initialized_ = false;
|
initialized_ = false;
|
||||||
Logger::info("ShaderManager released");
|
Logger::info("ShaderManager released");
|
||||||
|
|
@ -108,6 +109,15 @@ bool ShaderManager::load_builtin_shaders_() {
|
||||||
shader_cache_["raytracing"] = raytracing_shader_;
|
shader_cache_["raytracing"] = raytracing_shader_;
|
||||||
Logger::info("Ray tracing shader loaded successfully");
|
Logger::info("Ray tracing shader loaded successfully");
|
||||||
|
|
||||||
|
Logger::info("Loading denoise compute shader...");
|
||||||
|
denoise_shader_ = std::make_shared<Shader>();
|
||||||
|
if (!denoise_shader_->load_compute("shaders/denoiser.comp")) {
|
||||||
|
Logger::error("Failed to load denoise shader");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
shader_cache_["denoise"] = denoise_shader_;
|
||||||
|
Logger::info("Denoise shader loaded successfully");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue