From e160583feabe4c1c28e9107cb4d5be5e68861baf Mon Sep 17 00:00:00 2001 From: skal Date: Sun, 8 Feb 2026 17:09:15 +0100 Subject: feat(shaders): Add bump-mapped normal calculation variants Adds two new functions for displacement-mapped normal calculation: Functions added: - get_normal_bump(): High-quality 6-sample central differences - get_normal_bump_fast(): Optimized 4-sample tetrahedron pattern Performance comparison: - get_normal_bump: 6 SDF + 6 texture + 6 UV = 18 operations - get_normal_bump_fast: 4 SDF + 4 texture + 4 UV = 12 operations - Speed improvement: 33% faster with tetrahedron method Parameters: - p: Sample position (vec3) - obj_params: Object parameters (vec4) - noise_tex: Displacement texture (texture_2d) - noise_sampler: Texture sampler - disp_strength: Displacement strength multiplier Requirements: - spherical_uv() function must be available in calling context - get_dist() function must be available in calling context Use cases: - get_normal_bump: Static scenes, high-quality renders - get_normal_bump_fast: Real-time rendering, performance-critical paths Location: assets/final/shaders/math/sdf_utils.wgsl --- assets/final/shaders/math/sdf_utils.wgsl | 81 ++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'assets/final/shaders') diff --git a/assets/final/shaders/math/sdf_utils.wgsl b/assets/final/shaders/math/sdf_utils.wgsl index 3b06b93..660a4ce 100644 --- a/assets/final/shaders/math/sdf_utils.wgsl +++ b/assets/final/shaders/math/sdf_utils.wgsl @@ -25,6 +25,87 @@ fn get_normal_fast(p: vec3, obj_params: vec4) -> vec3 { ); } +// Bump-mapped normal using central differences (6 samples: SDF + texture). +// High quality, suitable for detailed surfaces with displacement mapping. +// Note: Requires spherical_uv() function and get_dist() to be available in calling context. +fn get_normal_bump( + p: vec3, + obj_params: vec4, + noise_tex: texture_2d, + noise_sampler: sampler, + disp_strength: f32 +) -> vec3 { + let e = vec2(0.005, 0.0); + + let q_x1 = p + e.xyy; + let uv_x1 = spherical_uv(q_x1); + let h_x1 = textureSample(noise_tex, noise_sampler, uv_x1).r; + let d_x1 = get_dist(q_x1, obj_params) - disp_strength * h_x1; + + let q_x2 = p - e.xyy; + let uv_x2 = spherical_uv(q_x2); + let h_x2 = textureSample(noise_tex, noise_sampler, uv_x2).r; + let d_x2 = get_dist(q_x2, obj_params) - disp_strength * h_x2; + + let q_y1 = p + e.yxy; + let uv_y1 = spherical_uv(q_y1); + let h_y1 = textureSample(noise_tex, noise_sampler, uv_y1).r; + let d_y1 = get_dist(q_y1, obj_params) - disp_strength * h_y1; + + let q_y2 = p - e.yxy; + let uv_y2 = spherical_uv(q_y2); + let h_y2 = textureSample(noise_tex, noise_sampler, uv_y2).r; + let d_y2 = get_dist(q_y2, obj_params) - disp_strength * h_y2; + + let q_z1 = p + e.yyx; + let uv_z1 = spherical_uv(q_z1); + let h_z1 = textureSample(noise_tex, noise_sampler, uv_z1).r; + let d_z1 = get_dist(q_z1, obj_params) - disp_strength * h_z1; + + let q_z2 = p - e.yyx; + let uv_z2 = spherical_uv(q_z2); + let h_z2 = textureSample(noise_tex, noise_sampler, uv_z2).r; + let d_z2 = get_dist(q_z2, obj_params) - disp_strength * h_z2; + + return normalize(vec3(d_x1 - d_x2, d_y1 - d_y2, d_z1 - d_z2)); +} + +// Optimized bump-mapped normal using tetrahedron pattern (4 samples instead of 6). +// 33% faster than get_normal_bump(), slightly less accurate. +// Suitable for real-time rendering with displacement mapping. +fn get_normal_bump_fast( + p: vec3, + obj_params: vec4, + noise_tex: texture_2d, + noise_sampler: sampler, + disp_strength: f32 +) -> vec3 { + let eps = 0.0005; + let k = vec2(1.0, -1.0); + + let q1 = p + k.xyy * eps; + let uv1 = spherical_uv(q1); + let h1 = textureSample(noise_tex, noise_sampler, uv1).r; + let d1 = get_dist(q1, obj_params) - disp_strength * h1; + + let q2 = p + k.yyx * eps; + let uv2 = spherical_uv(q2); + let h2 = textureSample(noise_tex, noise_sampler, uv2).r; + let d2 = get_dist(q2, obj_params) - disp_strength * h2; + + let q3 = p + k.yxy * eps; + let uv3 = spherical_uv(q3); + let h3 = textureSample(noise_tex, noise_sampler, uv3).r; + let d3 = get_dist(q3, obj_params) - disp_strength * h3; + + let q4 = p + k.xxx * eps; + let uv4 = spherical_uv(q4); + let h4 = textureSample(noise_tex, noise_sampler, uv4).r; + let d4 = get_dist(q4, obj_params) - disp_strength * h4; + + return normalize(k.xyy * d1 + k.yyx * d2 + k.yxy * d3 + k.xxx * d4); +} + // Distance to an Axis-Aligned Bounding Box fn aabb_sdf(p: vec3, min_p: vec3, max_p: vec3) -> f32 { let center = (min_p + max_p) * 0.5; -- cgit v1.2.3