Skip to content

Commit

Permalink
Fix gizmo lines deforming or disappearing when partially behind the c…
Browse files Browse the repository at this point in the history
…amera (#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.
  • Loading branch information
tim-blackbird authored Aug 17, 2023
1 parent 5fac1fe commit e2ed42f
Showing 1 changed file with 19 additions and 2 deletions.
21 changes: 19 additions & 2 deletions crates/bevy_gizmos/src/lines.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,13 @@ fn vertex(vertex: VertexInput) -> VertexOutput {
let position = positions[vertex.index];

// algorithm based on https://wwwtyro.net/2019/11/18/instanced-lines.html
let clip_a = view.view_proj * vec4(vertex.position_a, 1.);
let clip_b = view.view_proj * vec4(vertex.position_b, 1.);
var clip_a = view.view_proj * vec4(vertex.position_a, 1.);
var clip_b = view.view_proj * vec4(vertex.position_b, 1.);

// Manual near plane clipping to avoid errors when doing the perspective divide inside this shader.
clip_a = clip_near_plane(clip_a, clip_b);
clip_b = clip_near_plane(clip_b, clip_a);

let clip = mix(clip_a, clip_b, position.z);

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

fn clip_near_plane(a: vec4<f32>, b: vec4<f32>) -> vec4<f32> {
// 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<f32>,
};
Expand Down

0 comments on commit e2ed42f

Please sign in to comment.