aurora-rendering-engine/shaders/raytracing.comp

504 lines
16 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#version 430 core
// Constants
#define PI 3.14159265359
#define INV_PI 0.31830988618
#define EPSILON 1e-4
#define MAX_FLOAT 3.402823466e38
#define MAX_RAY_DEPTH 8
#define MAX_LIGHTS 16
// Material types
#define MATERIAL_DIFFUSE 0
#define MATERIAL_METAL 1
#define MATERIAL_DIELECTRIC 2
#define MATERIAL_EMISSIVE 3
// Light types
#define LIGHT_DIRECTIONAL 0
#define LIGHT_POINT 1
#define LIGHT_SPOT 2
// Structures
struct Material {
vec3 albedo;
float metallic;
vec3 emission;
float roughness;
int type;
float ior;
vec2 padding;
};
struct Light {
vec3 position;
int type;
vec3 direction;
float intensity;
vec3 color;
float range;
vec2 spot_angles; // inner, outer
vec2 padding;
};
struct Ray {
vec3 origin;
vec3 direction;
};
struct HitInfo {
bool hit;
float t;
vec3 position;
vec3 normal;
vec2 texcoord;
uint material_id;
};
// Utility functions
float saturate(float x) {
return clamp(x, 0.0, 1.0);
}
vec3 saturate(vec3 x) {
return clamp(x, vec3(0.0), vec3(1.0));
}
// Random number generation (PCG Hash)
uint pcg_hash(uint seed) {
uint state = seed * 747796405u + 2891336453u;
uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
return (word >> 22u) ^ word;
}
float random_float(inout uint seed) {
seed = pcg_hash(seed);
return float(seed) / 4294967296.0;
}
vec2 random_vec2(inout uint seed) {
return vec2(random_float(seed), random_float(seed));
}
vec3 random_vec3(inout uint seed) {
return vec3(random_float(seed), random_float(seed), random_float(seed));
}
// Random direction in hemisphere
vec3 random_hemisphere_direction(vec3 normal, inout uint seed) {
float z = random_float(seed);
float r = sqrt(max(0.0, 1.0 - z * z));
float phi = 2.0 * PI * random_float(seed);
vec3 dir = vec3(r * cos(phi), r * sin(phi), z);
// Create coordinate system
vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
vec3 tangent = normalize(cross(up, normal));
vec3 bitangent = cross(normal, tangent);
return normalize(tangent * dir.x + bitangent * dir.y + normal * dir.z);
}
// Cosine-weighted hemisphere sampling
// vec3 cosine_weighted_hemisphere(vec3 normal, inout uint seed) {
// vec2 r = random_vec2(seed);
// float r1 = 2.0 * PI * r.x;
// float r2 = r.y;
// float r2s = sqrt(r2);
//
// vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
// vec3 tangent = normalize(cross(up, normal));
// vec3 bitangent = cross(normal, tangent);
//
// vec3 dir = tangent * cos(r1) * r2s + bitangent * sin(r1) * r2s + normal * sqrt(1.0 - r2);
// return normalize(dir);
// }
// Schlick's approximation for Fresnel
vec3 fresnel_schlick(float cos_theta, vec3 f0) {
return f0 + (1.0 - f0) * pow(1.0 - cos_theta, 5.0);
}
// GGX distribution
float distribution_ggx(vec3 N, vec3 H, float roughness) {
float a = roughness * roughness;
float a2 = a * a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH * NdotH;
float nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return nom / max(denom, EPSILON);
}
// Smith's geometry function
float geometry_smith(vec3 N, vec3 V, vec3 L, float roughness) {
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float r = roughness + 1.0;
float k = (r * r) / 8.0;
float ggx1 = NdotV / (NdotV * (1.0 - k) + k);
float ggx2 = NdotL / (NdotL * (1.0 - k) + k);
return ggx1 * ggx2;
}
layout(local_size_x = 16, local_size_y = 16) in;
// G-Buffer inputs
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;
// Output
layout(binding = 3, rgba32f) uniform image2D output_image;
layout(binding = 4, rgba32f) uniform image2D accumulation_image;
// Scene data
layout(std430, binding = 0) readonly buffer MaterialBuffer {
Material materials[];
};
layout(std430, binding = 1) readonly buffer LightBuffer {
Light lights[];
};
// Uniforms
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;
// Evaluate direct lighting
vec3 evaluate_direct_lighting(vec3 position, vec3 normal, vec3 view_dir,
Material material, inout uint seed) {
vec3 direct_light = vec3(0.0);
for (uint i = 0u; i < u_light_count; i++) {
Light light = lights[i];
vec3 light_dir;
float light_distance;
float attenuation = 1.0;
if (light.type == LIGHT_POINT) {
vec3 to_light = light.position - position;
light_distance = length(to_light);
light_dir = to_light / light_distance;
attenuation = 1.0 / max(light_distance * light_distance, 0.01);
if (light_distance > light.range) continue;
} else if (light.type == LIGHT_DIRECTIONAL) {
light_dir = normalize(-light.direction);
light_distance = MAX_FLOAT;
} else {
continue;
}
float NdotL = max(dot(normal, light_dir), 0.0);
if (NdotL > 0.0) {
vec3 H = normalize(view_dir + light_dir);
float NdotV = max(dot(normal, view_dir), 0.0);
// PBR lighting
vec3 F0 = mix(vec3(0.04), material.albedo, material.metallic);
vec3 F = fresnel_schlick(max(dot(H, view_dir), 0.0), F0);
float D = distribution_ggx(normal, H, max(material.roughness, 0.04));
float G = geometry_smith(normal, view_dir, light_dir, material.roughness);
vec3 numerator = D * G * F;
float denominator = 4.0 * NdotV * NdotL + EPSILON;
vec3 specular = numerator / denominator;
vec3 kS = F;
vec3 kD = (vec3(1.0) - kS) * (1.0 - material.metallic);
vec3 radiance = light.color * light.intensity * attenuation;
direct_light += (kD * material.albedo * INV_PI + specular) * radiance * NdotL;
}
}
return direct_light;
}
void main() {
ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy);
ivec2 image_size = imageSize(output_image);
if (pixel_coords.x >= image_size.x || pixel_coords.y >= image_size.y) {
return;
}
// Read G-Buffer
vec4 position_data = imageLoad(g_position, pixel_coords);
vec4 normal_data = imageLoad(g_normal, pixel_coords);
vec4 albedo_data = imageLoad(g_albedo, pixel_coords);
// Background
if (position_data.w < 0.5) {
vec3 background = vec3(0.1, 0.1, 0.15);
imageStore(output_image, pixel_coords, vec4(background, 1.0));
imageStore(accumulation_image, pixel_coords, vec4(background, 1.0));
return;
}
vec3 position = position_data.xyz;
vec3 normal = normalize(normal_data.xyz);
vec3 albedo = albedo_data.rgb;
// 关键修复从G-Buffer的alpha通道读取material_id
// 注意albedo_data是从RGBA8纹理读取的alpha值范围是[0,1]
// 我们需要将其转换回整数ID
uint material_id = uint(albedo_data.a * 255.0 + 0.5);
// Initialize random seed
uint seed = uint(pixel_coords.x) + uint(pixel_coords.y) * uint(image_size.x) + u_frame_count * 719393u;
vec3 color = vec3(0.0);
// Get material from buffer
Material material;
uint mat_count = uint(materials.length());
if (material_id < mat_count) {
// 从SSBO读取材质
material = materials[material_id];
} else {
// 使用G-Buffer中的albedo作为fallback
material.albedo = albedo;
material.metallic = 0.0;
material.roughness = 0.5;
material.emission = vec3(0.0);
material.type = MATERIAL_DIFFUSE;
material.ior = 1.5;
}
// Add emission
color += material.emission;
// Direct lighting
vec3 view_dir = normalize(u_camera_position - position);
if (u_light_count > 0u) {
color += evaluate_direct_lighting(position, normal, view_dir, material, seed);
}
// Ambient lighting
color += material.albedo * 0.05;
// Clamp
color = clamp(color, vec3(0.0), vec3(10.0));
// Accumulation
if (u_enable_accumulation && u_frame_count > 0u) {
vec3 accumulated = imageLoad(accumulation_image, pixel_coords).rgb;
float weight = 1.0 / float(u_frame_count + 1u);
color = mix(accumulated, color, weight);
}
imageStore(accumulation_image, pixel_coords, vec4(color, 1.0));
imageStore(output_image, pixel_coords, vec4(color, 1.0));
}
// layout(local_size_x = 16, local_size_y = 16) in;
//
// // G-Buffer inputs
// 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;
//
// // Output
// layout(binding = 3, rgba32f) uniform image2D output_image;
// layout(binding = 4, rgba32f) uniform image2D accumulation_image;
//
// // Scene data
// layout(std430, binding = 0) readonly buffer MaterialBuffer {
// Material materials[];
// };
//
// layout(std430, binding = 1) readonly buffer LightBuffer {
// Light lights[];
// };
//
// // Uniforms
// 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;
//
// // Cosine-weighted hemisphere sampling
// vec3 cosine_weighted_hemisphere(vec3 normal, inout uint seed) {
// vec2 r = random_vec2(seed);
// float r1 = 2.0 * PI * r.x;
// float r2 = r.y;
// float r2s = sqrt(r2);
//
// vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
// vec3 tangent = normalize(cross(up, normal));
// vec3 bitangent = cross(normal, tangent);
//
// vec3 dir = tangent * cos(r1) * r2s + bitangent * sin(r1) * r2s + normal * sqrt(1.0 - r2);
// return normalize(dir);
// }
//
// // Evaluate direct lighting
// vec3 evaluate_direct_lighting(vec3 position, vec3 normal, vec3 view_dir,
// Material material, inout uint seed) {
// vec3 direct_light = vec3(0.0);
//
// for (uint i = 0u; i < u_light_count; i++) {
// Light light = lights[i];
// vec3 light_dir;
// float light_distance;
// float attenuation = 1.0;
//
// if (light.type == LIGHT_POINT) {
// vec3 to_light = light.position - position;
// light_distance = length(to_light);
// light_dir = to_light / light_distance;
// attenuation = 1.0 / max(light_distance * light_distance, 0.01);
//
// if (light_distance > light.range) continue;
// } else if (light.type == LIGHT_DIRECTIONAL) {
// light_dir = normalize(-light.direction);
// light_distance = MAX_FLOAT;
// } else {
// continue;
// }
//
// float NdotL = max(dot(normal, light_dir), 0.0);
//
// if (NdotL > 0.0) {
// vec3 H = normalize(view_dir + light_dir);
// float NdotV = max(dot(normal, view_dir), 0.0);
//
// // PBR lighting
// vec3 F0 = mix(vec3(0.04), material.albedo, material.metallic);
// vec3 F = fresnel_schlick(max(dot(H, view_dir), 0.0), F0);
// float D = distribution_ggx(normal, H, max(material.roughness, 0.04));
// float G = geometry_smith(normal, view_dir, light_dir, material.roughness);
//
// vec3 numerator = D * G * F;
// float denominator = 4.0 * NdotV * NdotL + EPSILON;
// vec3 specular = numerator / denominator;
//
// vec3 kS = F;
// vec3 kD = (vec3(1.0) - kS) * (1.0 - material.metallic);
//
// vec3 radiance = light.color * light.intensity * attenuation;
// direct_light += (kD * material.albedo * INV_PI + specular) * radiance * NdotL;
// }
// }
//
// return direct_light;
// }
//
// // Trace indirect lighting (simple path tracing)
// vec3 trace_indirect(vec3 position, vec3 normal, Material material, inout uint seed) {
// vec3 color = vec3(0.0);
//
// // Sample random direction
// vec3 ray_dir = cosine_weighted_hemisphere(normal, seed);
//
// // Sky color based on direction
// float t = 0.5 * (ray_dir.y + 1.0);
// vec3 sky_color = mix(vec3(1.0), vec3(0.5, 0.7, 1.0), t) * 0.2;
//
// color = sky_color;
//
// return color;
// }
//
// void main() {
// ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy);
// ivec2 image_size = imageSize(output_image);
//
// if (pixel_coords.x >= image_size.x || pixel_coords.y >= image_size.y) {
// return;
// }
//
// // Read G-Buffer
// vec4 position_data = imageLoad(g_position, pixel_coords);
// vec4 normal_data = imageLoad(g_normal, pixel_coords);
// vec4 albedo_data = imageLoad(g_albedo, pixel_coords);
//
// // Check if this pixel has valid geometry
// if (position_data.w < 0.5) {
// vec3 background = vec3(0.1, 0.1, 0.15);
// imageStore(output_image, pixel_coords, vec4(background, 1.0));
// imageStore(accumulation_image, pixel_coords, vec4(background, 1.0));
// return;
// }
//
// vec3 position = position_data.xyz;
// vec3 normal = normalize(normal_data.xyz);
// vec3 albedo = albedo_data.rgb;
// uint material_id = floatBitsToUint(albedo_data.a);
//
// if (material_id >= 1000u) {
// material_id = 0u;
// }
//
// // Initialize random seed
// uint seed = uint(pixel_coords.x) + uint(pixel_coords.y) * uint(image_size.x) + u_frame_count * 719393u;
//
// vec3 color = vec3(0.0);
//
// // Get material
// Material material;
// if (material_id < uint(materials.length())) {
// material = materials[material_id];
// } else {
// material.albedo = albedo;
// material.metallic = 0.0;
// material.roughness = 0.5;
// material.emission = vec3(0.0);
// material.type = MATERIAL_DIFFUSE;
// material.ior = 1.5;
// }
//
// // Add emission
// color += material.emission;
//
// // Direct lighting
// vec3 view_dir = normalize(u_camera_position - position);
//
// if (u_light_count > 0u) {
// color += evaluate_direct_lighting(position, normal, view_dir, material, seed);
// }
//
// // Indirect lighting (path tracing) - THIS ADDS NOISE
// for (uint samp_idx = 0u; samp_idx < u_samples_per_pixel; samp_idx++) { // 修复: sample -> samp_idx
// vec3 indirect = trace_indirect(position, normal, material, seed);
// color += indirect * material.albedo * INV_PI;
// }
//
// // Ambient
// color += material.albedo * 0.02;
//
// // Clamp
// color = clamp(color, vec3(0.0), vec3(100.0));
//
// // Accumulation for denoising
// if (u_enable_accumulation && u_frame_count > 0u) {
// vec3 accumulated = imageLoad(accumulation_image, pixel_coords).rgb;
// float weight = 1.0 / float(u_frame_count + 1u);
// color = mix(accumulated, color, weight);
// }
//
// imageStore(accumulation_image, pixel_coords, vec4(color, 1.0));
// imageStore(output_image, pixel_coords, vec4(color, 1.0));
// }