Skip to content

Commit e2ed42f

Browse files
Fix gizmo lines deforming or disappearing when partially behind the camera (#9470)
If a line has one point behind the camera(near plane) then it would deform or, if the `depth_bias` setting was set to a negative value, disappear. ## Solution The issue is that performing a perspective divide does not work correctly for points behind the near plane and a perspective divide is used inside the shader to define the line width in screen space. The solution is to perform near plane clipping manually inside the shader before the perspective divide is done.
1 parent 5fac1fe commit e2ed42f

File tree

1 file changed

+19
-2
lines changed

1 file changed

+19
-2
lines changed

crates/bevy_gizmos/src/lines.wgsl

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,13 @@ fn vertex(vertex: VertexInput) -> VertexOutput {
4343
let position = positions[vertex.index];
4444

4545
// algorithm based on https://wwwtyro.net/2019/11/18/instanced-lines.html
46-
let clip_a = view.view_proj * vec4(vertex.position_a, 1.);
47-
let clip_b = view.view_proj * vec4(vertex.position_b, 1.);
46+
var clip_a = view.view_proj * vec4(vertex.position_a, 1.);
47+
var clip_b = view.view_proj * vec4(vertex.position_b, 1.);
48+
49+
// Manual near plane clipping to avoid errors when doing the perspective divide inside this shader.
50+
clip_a = clip_near_plane(clip_a, clip_b);
51+
clip_b = clip_near_plane(clip_b, clip_a);
52+
4853
let clip = mix(clip_a, clip_b, position.z);
4954

5055
let resolution = view.viewport.zw;
@@ -92,6 +97,18 @@ fn vertex(vertex: VertexInput) -> VertexOutput {
9297
return VertexOutput(clip_position, color);
9398
}
9499

100+
fn clip_near_plane(a: vec4<f32>, b: vec4<f32>) -> vec4<f32> {
101+
// Move a if a is behind the near plane and b is in front.
102+
if a.z > a.w && b.z <= b.w {
103+
// Interpolate a towards b until it's at the near plane.
104+
let distance_a = a.z - a.w;
105+
let distance_b = b.z - b.w;
106+
let t = distance_a / (distance_a - distance_b);
107+
return a + (b - a) * t;
108+
}
109+
return a;
110+
}
111+
95112
struct FragmentInput {
96113
@location(0) color: vec4<f32>,
97114
};

0 commit comments

Comments
 (0)