feat&fix: 优化shaders

- fix: 修复raytracing.comp random_in_unit_sphere()死循环

- fix: 合并raytracing.comp相机光线生成函数
- feat: 将denoiser.comp修改为双边滤波降噪
- chore: 格式化shader注释
master
ternaryop8479 2026-03-28 09:54:02 +08:00
parent 687a79b526
commit d7f5c7e5cc
3 changed files with 48 additions and 38 deletions

Binary file not shown.

View File

@ -7,22 +7,47 @@ layout(binding = 1, rgba32f) uniform writeonly image2D u_output;
uniform int u_radius; // 1 => 3x3, 2 => 5x5 uniform int u_radius; // 1 => 3x3, 2 => 5x5
// Gaussian weight based on distance
float gaussian_weight(float dist, float sigma) {
return exp(-0.5 * dist * dist / (sigma * sigma));
}
// Bilateral filter: considers both spatial distance and color similarity
void main() { void main() {
ivec2 p = ivec2(gl_GlobalInvocationID.xy); ivec2 p = ivec2(gl_GlobalInvocationID.xy);
ivec2 size = imageSize(u_output); ivec2 size = imageSize(u_output);
if (p.x >= size.x || p.y >= size.y) return; if (p.x >= size.x || p.y >= size.y) return;
vec3 center_color = imageLoad(u_input, p).rgb;
// Sigma values for bilateral filter
float sigma_space = float(u_radius); // spatial sigma
float sigma_color = 0.3; // color sigma (adjust for more/less smoothing)
vec3 sum = vec3(0.0); vec3 sum = vec3(0.0);
int count = 0; float weight_sum = 0.0;
for (int dy = -u_radius; dy <= u_radius; ++dy) { for (int dy = -u_radius; dy <= u_radius; ++dy) {
for (int dx = -u_radius; dx <= u_radius; ++dx) { for (int dx = -u_radius; dx <= u_radius; ++dx) {
ivec2 q = clamp(p + ivec2(dx, dy), ivec2(0), size - ivec2(1)); ivec2 q = clamp(p + ivec2(dx, dy), ivec2(0), size - ivec2(1));
sum += imageLoad(u_input, q).rgb; vec3 sample_color = imageLoad(u_input, q).rgb;
count += 1;
// Spatial weight (Gaussian based on distance)
float spatial_dist = length(vec2(float(dx), float(dy)));
float spatial_weight = gaussian_weight(spatial_dist, sigma_space);
// Color weight (Gaussian based on color difference)
float color_dist = length(sample_color - center_color);
float color_weight = gaussian_weight(color_dist, sigma_color);
// Combined bilateral weight
float weight = spatial_weight * color_weight;
sum += sample_color * weight;
weight_sum += weight;
} }
} }
vec3 out_color = sum / float(count); vec3 out_color = sum / max(weight_sum, 1e-6);
imageStore(u_output, p, vec4(out_color, 1.0)); imageStore(u_output, p, vec4(out_color, 1.0));
} }

View File

@ -139,21 +139,21 @@ vec4 sample_texture_array(int slot, int index, vec2 uv) {
// Utility // Utility
// ============================================================================ // ============================================================================
/** /*
* @brief Check if vector is near zero * @brief Check if vector is near zero
*/ */
bool near_zero(vec3 v) { bool near_zero(vec3 v) {
return (abs(v.x) < EPSILON) && (abs(v.y) < EPSILON) && (abs(v.z) < EPSILON); return (abs(v.x) < EPSILON) && (abs(v.y) < EPSILON) && (abs(v.z) < EPSILON);
} }
/** /*
* @brief Reflect vector around normal * @brief Reflect vector around normal
*/ */
vec3 reflect_vector(vec3 v, vec3 n) { vec3 reflect_vector(vec3 v, vec3 n) {
return v - 2.0 * dot(v, n) * n; return v - 2.0 * dot(v, n) * n;
} }
/** /*
* @brief Refract vector through surface * @brief Refract vector through surface
*/ */
vec3 refract_vector(vec3 uv, vec3 n, float etai_over_etat) { vec3 refract_vector(vec3 uv, vec3 n, float etai_over_etat) {
@ -186,10 +186,11 @@ vec3 random_vec3(inout uint seed) {
} }
vec3 random_in_unit_sphere(inout uint seed) { vec3 random_in_unit_sphere(inout uint seed) {
while (true) { // Use cosine-weighted hemisphere sampling to avoid infinite loop
vec3 p = 2.0 * random_vec3(seed) - vec3(1.0); float z = 1.0 - 2.0 * random_float(seed);
if (dot(p, p) < 1.0) return p; float r = sqrt(max(0.0, 1.0 - z * z));
} float phi = 2.0 * PI * random_float(seed);
return vec3(r * cos(phi), r * sin(phi), z);
} }
vec3 random_unit_vector(inout uint seed) { vec3 random_unit_vector(inout uint seed) {
@ -200,12 +201,11 @@ vec3 random_unit_vector(inout uint seed) {
// Camera ray // Camera ray
// ============================================================================ // ============================================================================
/** /*
* @brief Generate primary ray in world space * @brief Generate primary ray in world space (center pixel, no jitter)
*/ */
Ray generate_camera_ray(ivec2 pixel_coords, ivec2 image_size, inout uint seed) { Ray generate_camera_ray(ivec2 pixel_coords, ivec2 image_size) {
vec2 jitter = vec2(random_float(seed), random_float(seed)); vec2 uv = (vec2(pixel_coords) + vec2(0.5)) / vec2(image_size);
vec2 uv = (vec2(pixel_coords) + jitter) / vec2(image_size);
vec2 ndc = uv * 2.0 - 1.0; vec2 ndc = uv * 2.0 - 1.0;
vec4 p_near = u_inv_view_projection * vec4(ndc, 0.0, 1.0); vec4 p_near = u_inv_view_projection * vec4(ndc, 0.0, 1.0);
@ -223,7 +223,7 @@ Ray generate_camera_ray(ivec2 pixel_coords, ivec2 image_size, inout uint seed) {
// Intersection // Intersection
// ============================================================================ // ============================================================================
/** /*
* @brief Ray-AABB intersection * @brief Ray-AABB intersection
*/ */
bool intersect_aabb(Ray ray, vec3 aabb_min, vec3 aabb_max, float t_max) { bool intersect_aabb(Ray ray, vec3 aabb_min, vec3 aabb_max, float t_max) {
@ -240,7 +240,7 @@ bool intersect_aabb(Ray ray, vec3 aabb_min, vec3 aabb_max, float t_max) {
return (tmax2 >= max(tmin, 0.0)) && (tmin <= t_max); return (tmax2 >= max(tmin, 0.0)) && (tmin <= t_max);
} }
/** /*
* @brief Moller-Trumbore triangle intersection * @brief Moller-Trumbore triangle intersection
*/ */
bool intersect_triangle(Ray ray, TriangleGpu tri, inout HitInfo hit) { bool intersect_triangle(Ray ray, TriangleGpu tri, inout HitInfo hit) {
@ -295,7 +295,7 @@ bool intersect_triangle(Ray ray, TriangleGpu tri, inout HitInfo hit) {
return true; return true;
} }
/** /*
* @brief BVH traversal (closest hit) * @brief BVH traversal (closest hit)
*/ */
HitInfo trace_ray_bvh(Ray ray) { HitInfo trace_ray_bvh(Ray ray) {
@ -339,7 +339,7 @@ HitInfo trace_ray_bvh(Ray ray) {
return hit; return hit;
} }
/** /*
* @brief Any-hit BVH for shadow ray * @brief Any-hit BVH for shadow ray
*/ */
bool trace_any_bvh(Ray ray, float t_max) { bool trace_any_bvh(Ray ray, float t_max) {
@ -385,7 +385,7 @@ bool trace_any_bvh(Ray ray, float t_max) {
// Primary-ray fast path via G-Buffer // Primary-ray fast path via G-Buffer
// ============================================================================ // ============================================================================
/** /*
* @brief Read primary hit from G-Buffer if current pixel has geometry * @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). * @note Uses g_position.w as "valid" marker (your gbuffer writes 1.0 on hits, clear is 0).
*/ */
@ -648,26 +648,11 @@ vec3 environment_color(vec3 dir) {
return vec3(0.1, 0.1, 0.15); return vec3(0.1, 0.1, 0.15);
} }
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 * @brief Trace path with primary-ray G-Buffer acceleration
*/ */
vec3 trace_path_primary_gbuffer(ivec2 pixel_coords, ivec2 image_size, inout uint seed) { vec3 trace_path_primary_gbuffer(ivec2 pixel_coords, ivec2 image_size, inout uint seed) {
Ray ray = generate_camera_ray_center(pixel_coords, image_size); Ray ray = generate_camera_ray(pixel_coords, image_size);
vec3 radiance = vec3(0.0); vec3 radiance = vec3(0.0);
vec3 throughput = vec3(1.0); vec3 throughput = vec3(1.0);