From 7b2213a5f3103f3e6e6b24d531735b4b8fcdf5ee Mon Sep 17 00:00:00 2001 From: irate Date: Tue, 14 Nov 2023 23:36:02 +0100 Subject: [PATCH] Fix float precision issue in the gizmo shader (#10408) Fix a precision issue with in the manual near-clipping function. This only affected lines that span large distances (starting at 100_000~ units) in my testing. Fixes #10403 --- crates/bevy_gizmos/src/lines.wgsl | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/bevy_gizmos/src/lines.wgsl b/crates/bevy_gizmos/src/lines.wgsl index 2eb6ef907aeb8..d5c9e1e1476eb 100644 --- a/crates/bevy_gizmos/src/lines.wgsl +++ b/crates/bevy_gizmos/src/lines.wgsl @@ -28,6 +28,8 @@ struct VertexOutput { @location(0) color: vec4, }; +const EPSILON: f32 = 4.88e-04; + @vertex fn vertex(vertex: VertexInput) -> VertexOutput { var positions = array, 6>( @@ -79,7 +81,6 @@ fn vertex(vertex: VertexInput) -> VertexOutput { if line_gizmo.depth_bias >= 0. { depth = clip.z * (1. - line_gizmo.depth_bias); } else { - let epsilon = 4.88e-04; // depth * (clip.w / depth)^-depth_bias. So that when -depth_bias is 1.0, this is equal to clip.w // and when equal to 0.0, it is exactly equal to depth. // the epsilon is here to prevent the depth from exceeding clip.w when -depth_bias = 1.0 @@ -87,7 +88,7 @@ fn vertex(vertex: VertexInput) -> VertexOutput { // of this value means nothing can be in front of this // The reason this uses an exponential function is that it makes it much easier for the // user to chose a value that is convenient for them - depth = clip.z * exp2(-line_gizmo.depth_bias * log2(clip.w / clip.z - epsilon)); + depth = clip.z * exp2(-line_gizmo.depth_bias * log2(clip.w / clip.z - EPSILON)); } var clip_position = vec4(clip.w * ((2. * screen) / resolution - 1.), depth, clip.w); @@ -101,8 +102,10 @@ fn clip_near_plane(a: vec4, b: vec4) -> vec4 { // Interpolate a towards b until it's at the near plane. let distance_a = a.z - a.w; let distance_b = b.z - b.w; - let t = distance_a / (distance_a - distance_b); - return a + (b - a) * t; + // Add an epsilon to the interpolator to ensure that the point is + // not just behind the clip plane due to floating-point imprecision. + let t = distance_a / (distance_a - distance_b) + EPSILON; + return mix(a, b, t); } return a; }