refactor: 优化shader代码,消除性能瓶颈和代码重复

- 重构BVH三角形相交函数,统一trace_ray_bvh和trace_any_bvh的相交检测
- 修复Windows平台binding point限制,将g_texcoord从7改为2,g_tangent从8改为7
- 优化Fresnel计算,scatter_dielectric_sobol调用fresnel_dielectric函数消除内联重复
- 删除6处冗余normalize调用(material.glsl和raytracing.comp中的scatter函数)
- 纹理数组支持per-slot哈希缓存,避免每帧重建
main
ternaryop8479 2026-04-11 22:44:46 +08:00
parent 65f2386b27
commit adfe38a453
4 changed files with 55 additions and 73 deletions

View File

@ -40,7 +40,8 @@ bool intersect_aabb(Ray ray, vec3 aabb_min, vec3 aabb_max, float t_max) {
// Moller-Trumbore triangle intersection using compact triangle (precomputed edges) // Moller-Trumbore triangle intersection using compact triangle (precomputed edges)
// Uses TriangleCompactGpu: v0_material, e1=v1-v0, e2=v2-v0 // Uses TriangleCompactGpu: v0_material, e1=v1-v0, e2=v2-v0
bool intersect_triangle_compact(Ray ray, TriangleCompactGpu tri, inout HitInfo hit) { // Returns true if hit, outputs barycentric coords (u, v) and distance t
bool intersect_triangle_compact(Ray ray, TriangleCompactGpu tri, float t_max, out float out_t, out float out_u, out float out_v) {
vec3 v0 = tri.v0_material.xyz; vec3 v0 = tri.v0_material.xyz;
vec3 e1 = tri.e1.xyz; vec3 e1 = tri.e1.xyz;
vec3 e2 = tri.e2.xyz; vec3 e2 = tri.e2.xyz;
@ -60,18 +61,37 @@ bool intersect_triangle_compact(Ray ray, TriangleCompactGpu tri, inout HitInfo h
if (v < 0.0 || u + v > 1.0) return false; if (v < 0.0 || u + v > 1.0) return false;
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 >= t_max) return false;
float w = 1.0 - u - v; out_t = t;
out_u = u;
out_v = v;
return true;
}
// Fetch attributes only after confirmed hit // Check if triangle is hit (for shadow rays - no barycentric needed)
TriangleAttrGpu attr = bvh_attrs[gl_GlobalInvocationID.x]; bool intersect_triangle_any(Ray ray, TriangleCompactGpu tri, float t_max) {
// We need the triangle index, not invocation ID. Use a different approach. vec3 v0 = tri.v0_material.xyz;
vec3 e1 = tri.e1.xyz;
vec3 e2 = tri.e2.xyz;
vec3 pvec = cross(ray.direction, e2);
float det = dot(e1, pvec);
if (abs(det) < EPSILON) return false;
float inv_det = 1.0 / det;
vec3 tvec = ray.origin - v0;
float u = dot(tvec, pvec) * inv_det;
if (u < 0.0 || u > 1.0) return false;
vec3 qvec = cross(tvec, e1);
float v = dot(ray.direction, qvec) * inv_det;
if (v < 0.0 || u + v > 1.0) return false;
float t = dot(e2, qvec) * inv_det;
if (t < EPSILON || t >= t_max) return false;
hit.hit = true;
hit.t = t;
hit.position = ray.origin + t * ray.direction;
hit.material_id = as_uint(tri.v0_material.w);
return true; return true;
} }
@ -131,35 +151,17 @@ HitInfo trace_ray_bvh(Ray ray) {
for (uint i = 0u; i < count; ++i) { for (uint i = 0u; i < count; ++i) {
uint tri_idx = left_first + i; uint tri_idx = left_first + i;
TriangleCompactGpu tri = bvh_tris[tri_idx]; TriangleCompactGpu tri = bvh_tris[tri_idx];
vec3 v0 = tri.v0_material.xyz;
vec3 e1 = tri.e1.xyz; float t, u, v;
vec3 e2 = tri.e2.xyz; if (intersect_triangle_compact(ray, tri, hit.t, t, u, v)) {
hit.hit = true;
vec3 pvec = cross(ray.direction, e2); hit.t = t;
float det = dot(e1, pvec); hit.position = ray.origin + t * ray.direction;
hit.material_id = as_uint(tri.v0_material.w);
if (abs(det) < EPSILON) continue; hit_tri_idx = tri_idx;
float inv_det = 1.0 / det; hit_u = u;
hit_v = v;
vec3 tvec = ray.origin - v0; }
float u = dot(tvec, pvec) * inv_det;
if (u < 0.0 || u > 1.0) continue;
vec3 qvec = cross(tvec, e1);
float v = dot(ray.direction, qvec) * inv_det;
if (v < 0.0 || u + v > 1.0) continue;
float t = dot(e2, qvec) * inv_det;
if (t < EPSILON || t >= hit.t) continue;
// Record hit but defer attribute fetch
hit.hit = true;
hit.t = t;
hit.position = ray.origin + t * ray.direction;
hit.material_id = as_uint(tri.v0_material.w);
hit_tri_idx = tri_idx;
hit_u = u;
hit_v = v;
} }
} else { } else {
uint left = left_first; uint left = left_first;
@ -239,28 +241,9 @@ 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) {
TriangleCompactGpu tri = bvh_tris[left_first + i]; TriangleCompactGpu tri = bvh_tris[left_first + i];
vec3 v0 = tri.v0_material.xyz; if (intersect_triangle_any(ray, tri, t_max)) {
vec3 e1 = tri.e1.xyz; return true;
vec3 e2 = tri.e2.xyz; }
vec3 pvec = cross(ray.direction, e2);
float det = dot(e1, pvec);
if (abs(det) < EPSILON) continue;
float inv_det = 1.0 / det;
vec3 tvec = ray.origin - v0;
float u = dot(tvec, pvec) * inv_det;
if (u < 0.0 || u > 1.0) continue;
vec3 qvec = cross(tvec, e1);
float v = dot(ray.direction, qvec) * inv_det;
if (v < 0.0 || u + v > 1.0) continue;
float t = dot(e2, qvec) * inv_det;
if (t < EPSILON || t >= t_max) continue;
return true;
} }
} else { } else {
uint left = left_first; uint left = left_first;

View File

@ -87,7 +87,7 @@ ScatterResult scatter_diffuse(Ray ray_in, HitInfo hit, Material mat, inout uint
if (near_zero(dir)) dir = hit.normal; if (near_zero(dir)) dir = hit.normal;
r.scattered_ray.origin = hit.position + hit.normal * EPSILON; r.scattered_ray.origin = hit.position + hit.normal * EPSILON;
r.scattered_ray.direction = normalize(dir); r.scattered_ray.direction = dir;
return r; return r;
} }
@ -127,7 +127,7 @@ ScatterResult scatter_metal(Ray ray_in, HitInfo hit, Material mat, inout uint se
r.scattered = true; r.scattered = true;
r.scattered_ray.origin = hit.position + N * EPSILON; r.scattered_ray.origin = hit.position + N * EPSILON;
r.scattered_ray.direction = normalize(L); r.scattered_ray.direction = L;
return r; return r;
} }
@ -158,7 +158,7 @@ ScatterResult scatter_dielectric(Ray ray_in, HitInfo hit, Material mat, inout ui
} }
r.scattered_ray.origin = hit.position + dir * EPSILON; r.scattered_ray.origin = hit.position + dir * EPSILON;
r.scattered_ray.direction = normalize(dir); r.scattered_ray.direction = dir;
return r; return r;
} }

View File

@ -16,8 +16,8 @@ layout(binding = 0, rgba32f) uniform readonly image2D g_position;
layout(binding = 1, rg32f) uniform readonly image2D g_normal; // Octahedral encoded layout(binding = 1, rg32f) uniform readonly image2D g_normal; // Octahedral encoded
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;
layout(binding = 7, rgba32f) uniform readonly image2D g_texcoord; layout(binding = 2, rgba32f) uniform readonly image2D g_texcoord;
layout(binding = 8, rgba32f) uniform readonly image2D g_tangent; layout(binding = 7, rgba32f) uniform readonly image2D g_tangent;
// Output // Output
layout(binding = 3, rgba32f) uniform image2D output_image; layout(binding = 3, rgba32f) uniform image2D output_image;
@ -130,7 +130,7 @@ ScatterResult scatter_diffuse_sobol(Ray ray_in, HitInfo hit, Material mat, inout
if (near_zero(dir)) dir = hit.normal; if (near_zero(dir)) dir = hit.normal;
r.scattered_ray.origin = hit.position + hit.normal * EPSILON; r.scattered_ray.origin = hit.position + hit.normal * EPSILON;
r.scattered_ray.direction = normalize(dir); r.scattered_ray.direction = dir;
return r; return r;
} }
@ -160,7 +160,7 @@ ScatterResult scatter_metal_sobol(Ray ray_in, HitInfo hit, Material mat, inout S
r.attenuation = clamp(F, vec3(0.0), vec3(1.0)); r.attenuation = clamp(F, vec3(0.0), vec3(1.0));
r.scattered = true; r.scattered = true;
r.scattered_ray.origin = hit.position + N * EPSILON; r.scattered_ray.origin = hit.position + N * EPSILON;
r.scattered_ray.direction = normalize(L); r.scattered_ray.direction = L;
return r; return r;
} }
@ -181,8 +181,7 @@ ScatterResult scatter_dielectric_sobol(Ray ray_in, HitInfo hit, Material mat, in
float sin_theta_t = eta * sin_theta; float sin_theta_t = eta * sin_theta;
bool total_internal_reflection = sin_theta_t >= 1.0; bool total_internal_reflection = sin_theta_t >= 1.0;
float f0 = pow((1.0 - mat.ior) / (1.0 + mat.ior), 2.0); float f = fresnel_dielectric(cos_theta, mat.ior);
float f = f0 + (1.0 - f0) * pow(1.0 - abs(cos_theta), 5.0);
vec3 dir; vec3 dir;
if (total_internal_reflection || sobol_next(state) < f) { if (total_internal_reflection || sobol_next(state) < f) {
@ -192,7 +191,7 @@ ScatterResult scatter_dielectric_sobol(Ray ray_in, HitInfo hit, Material mat, in
} }
r.scattered_ray.origin = hit.position + dir * EPSILON; r.scattered_ray.origin = hit.position + dir * EPSILON;
r.scattered_ray.direction = normalize(dir); r.scattered_ray.direction = dir;
return r; return r;
} }

View File

@ -420,10 +420,10 @@ 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);
// Texcoord // Texcoord
glBindImageTexture(7, gbuffer.get_texture(GBUFFER_TEXCOORD), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); glBindImageTexture(2, gbuffer.get_texture(GBUFFER_TEXCOORD), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
// Tangent // Tangent
glBindImageTexture(8, gbuffer.get_texture(GBUFFER_TANGENT), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); glBindImageTexture(7, gbuffer.get_texture(GBUFFER_TANGENT), 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F);
} }
void RayTracer::build_texture_arrays_(const Scene &scene) { void RayTracer::build_texture_arrays_(const Scene &scene) {