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)
// 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 e1 = tri.e1.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;
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
TriangleAttrGpu attr = bvh_attrs[gl_GlobalInvocationID.x];
// We need the triangle index, not invocation ID. Use a different approach.
// Check if triangle is hit (for shadow rays - no barycentric needed)
bool intersect_triangle_any(Ray ray, TriangleCompactGpu tri, float t_max) {
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;
}
@ -131,28 +151,9 @@ HitInfo trace_ray_bvh(Ray ray) {
for (uint i = 0u; i < count; ++i) {
uint tri_idx = left_first + i;
TriangleCompactGpu tri = bvh_tris[tri_idx];
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) 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 >= hit.t) continue;
// Record hit but defer attribute fetch
float t, u, v;
if (intersect_triangle_compact(ray, tri, hit.t, t, u, v)) {
hit.hit = true;
hit.t = t;
hit.position = ray.origin + t * ray.direction;
@ -161,6 +162,7 @@ HitInfo trace_ray_bvh(Ray ray) {
hit_u = u;
hit_v = v;
}
}
} else {
uint left = left_first;
uint right = left_first + 1u;
@ -239,29 +241,10 @@ bool trace_any_bvh(Ray ray, float t_max) {
if (count > 0u) {
for (uint i = 0u; i < count; ++i) {
TriangleCompactGpu tri = bvh_tris[left_first + i];
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) 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;
if (intersect_triangle_any(ray, tri, t_max)) {
return true;
}
}
} else {
uint left = left_first;
uint right = left_first + 1u;

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;
r.scattered_ray.origin = hit.position + hit.normal * EPSILON;
r.scattered_ray.direction = normalize(dir);
r.scattered_ray.direction = dir;
return r;
}
@ -127,7 +127,7 @@ ScatterResult scatter_metal(Ray ray_in, HitInfo hit, Material mat, inout uint se
r.scattered = true;
r.scattered_ray.origin = hit.position + N * EPSILON;
r.scattered_ray.direction = normalize(L);
r.scattered_ray.direction = L;
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.direction = normalize(dir);
r.scattered_ray.direction = dir;
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 = 5, rgba32f) uniform readonly image2D g_material;
layout(binding = 6, r32ui) uniform readonly uimage2D g_material_id;
layout(binding = 7, rgba32f) uniform readonly image2D g_texcoord;
layout(binding = 8, rgba32f) uniform readonly image2D g_tangent;
layout(binding = 2, rgba32f) uniform readonly image2D g_texcoord;
layout(binding = 7, rgba32f) uniform readonly image2D g_tangent;
// Output
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;
r.scattered_ray.origin = hit.position + hit.normal * EPSILON;
r.scattered_ray.direction = normalize(dir);
r.scattered_ray.direction = dir;
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.scattered = true;
r.scattered_ray.origin = hit.position + N * EPSILON;
r.scattered_ray.direction = normalize(L);
r.scattered_ray.direction = L;
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;
bool total_internal_reflection = sin_theta_t >= 1.0;
float f0 = pow((1.0 - mat.ior) / (1.0 + mat.ior), 2.0);
float f = f0 + (1.0 - f0) * pow(1.0 - abs(cos_theta), 5.0);
float f = fresnel_dielectric(cos_theta, mat.ior);
vec3 dir;
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.direction = normalize(dir);
r.scattered_ray.direction = dir;
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);
// 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
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) {