From 4b70125a92293c613f425702d9d0fe78c08c6881 Mon Sep 17 00:00:00 2001 From: devil-ira Date: Thu, 17 Aug 2023 16:56:48 +0200 Subject: [PATCH] Fix issues with lines that are partially behind the near plane --- src/shaders/polyline.wgsl | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/shaders/polyline.wgsl b/src/shaders/polyline.wgsl index b75a16b..a31e64e 100644 --- a/src/shaders/polyline.wgsl +++ b/src/shaders/polyline.wgsl @@ -43,8 +43,13 @@ fn vertex(vertex: Vertex) -> VertexOutput { let position = positions[vertex.index]; // algorithm based on https://wwwtyro.net/2019/11/18/instanced-lines.html - let clip0 = view.view_proj * polyline.model * vec4(vertex.point_a, 1.0); - let clip1 = view.view_proj * polyline.model * vec4(vertex.point_b, 1.0); + var clip0 = view.view_proj * polyline.model * vec4(vertex.point_a, 1.0); + var clip1 = view.view_proj * polyline.model * vec4(vertex.point_b, 1.0); + + // Manual near plane clipping to avoid errors when doing the perspective divide inside this shader. + clip0 = clip_near_plane(clip0, clip1); + clip1 = clip_near_plane(clip1, clip0); + let clip = mix(clip0, clip1, position.z); let resolution = vec2(view.viewport.z, view.viewport.w); @@ -89,6 +94,18 @@ fn vertex(vertex: Vertex) -> VertexOutput { return VertexOutput(vec4(clip.w * ((2.0 * pt) / resolution - 1.0), depth, clip.w), color); } +fn clip_near_plane(a: vec4, b: vec4) -> vec4 { + // Move a if a is behind the near plane and b is in front. + if a.z > a.w && b.z <= b.w { + // 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; + } + return a; +} + struct FragmentInput { @location(0) color: vec4, };