diff --git a/src/shaders/polyline.wgsl b/src/shaders/polyline.wgsl index 2ebde5a..51db16e 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, };