Fix Z-fighting between overlay and stencil with OpenGL wgpu back-end.

This commit is contained in:
Robin KAY 2023-05-30 21:51:13 +01:00
parent 4a8d4409fe
commit 35032e05a3
5 changed files with 56 additions and 17 deletions

View File

@ -20,6 +20,7 @@ bevy = { version = "0.10", default-features = false, features = [
bitfield = "0.14"
interpolation = "0.2"
thiserror = "1.0"
wgpu-types = "0.15"
[dev-dependencies]
bevy = { version = "0.10", default-features = false, features = [

View File

@ -3,7 +3,9 @@ use bevy::prelude::*;
use bevy::render::render_asset::RenderAssets;
use bevy::render::render_phase::{DrawFunctions, RenderPhase, SetItemPipeline};
use bevy::render::render_resource::{PipelineCache, SpecializedMeshPipelines};
use bevy::render::renderer::RenderAdapterInfo;
use bevy::render::view::{ExtractedView, RenderLayers};
use wgpu_types::Backend;
use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline};
use crate::pipeline::{OutlinePipeline, PassType, PipelineKey};
@ -32,6 +34,7 @@ pub(crate) fn queue_outline_stencil_mesh(
mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>,
pipeline_cache: Res<PipelineCache>,
render_meshes: Res<RenderAssets<Mesh>>,
adapter_info: Res<RenderAdapterInfo>,
material_meshes: Query<(
Entity,
&Handle<Mesh>,
@ -52,7 +55,8 @@ pub(crate) fn queue_outline_stencil_mesh(
let base_key = PipelineKey::new()
.with_msaa(*msaa)
.with_pass_type(PassType::Stencil);
.with_pass_type(PassType::Stencil)
.with_opengl_workaround(adapter_info.0.backend == Backend::Gl);
for (view, mut stencil_phase, view_mask) in views.iter_mut() {
let rangefinder = view.rangefinder3d();
@ -105,6 +109,7 @@ pub(crate) fn queue_outline_volume_mesh(
mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>,
pipeline_cache: Res<PipelineCache>,
render_meshes: Res<RenderAssets<Mesh>>,
adapter_info: Res<RenderAdapterInfo>,
material_meshes: Query<(
Entity,
&Handle<Mesh>,
@ -129,7 +134,9 @@ pub(crate) fn queue_outline_volume_mesh(
.get_id::<DrawOutline>()
.unwrap();
let base_key = PipelineKey::new().with_msaa(*msaa);
let base_key = PipelineKey::new()
.with_msaa(*msaa)
.with_opengl_workaround(adapter_info.0.backend == Backend::Gl);
for (view, mut opaque_phase, mut transparent_phase, view_mask) in views.iter_mut() {
let view_mask = view_mask.copied().unwrap_or_default();

View File

@ -1,24 +1,32 @@
#ifdef VOLUME
struct FragmentOutput {
@location(0) colour: vec4<f32>,
#ifdef OPENGL_WORKAROUND
@builtin(frag_depth) frag_depth: f32,
#endif
};
struct OutlineFragmentUniform {
@align(16)
colour: vec4<f32>,
};
#ifdef VOLUME
@group(3) @binding(1)
var<uniform> fstage: OutlineFragmentUniform;
#endif
@fragment
fn fragment() -> @location(0) vec4<f32> {
return fstage.colour;
}
#ifdef OPENGL_WORKAROUND
fn fragment(@location(0) normalised_depth: f32) -> FragmentOutput {
#else
// Stencil
@fragment
fn fragment() {
return;
}
#endif
fn fragment() -> FragmentOutput {
#endif
var out: FragmentOutput;
#ifdef VOLUME
out.colour = fstage.colour;
#endif
#ifdef OPENGL_WORKAROUND
out.frag_depth = normalised_depth;
#endif
return out;
}

View File

@ -12,6 +12,13 @@ struct VertexInput {
#endif
};
struct VertexOutput {
@builtin(position) position: vec4<f32>,
#ifdef OPENGL_WORKAROUND
@location(0) normalised_depth: f32,
#endif
};
struct OutlineViewUniform {
@align(16)
scale: vec2<f32>,
@ -53,7 +60,7 @@ fn model_origin_z(plane: vec3<f32>, view_proj: mat4x4<f32>) -> f32 {
}
@vertex
fn vertex(vertex: VertexInput) -> @builtin(position) vec4<f32> {
fn vertex(vertex: VertexInput) -> VertexOutput {
#ifdef SKINNED
let model = skin_model(vertex.joint_indexes, vertex.joint_weights);
#else
@ -72,5 +79,10 @@ fn vertex(vertex: VertexInput) -> @builtin(position) vec4<f32> {
let ndc_delta = vstage.offset * normalize(clip_norm.xy) * view_uniform.scale * clip_pos.w;
let out_xy = clip_pos.xy + ndc_delta;
#endif
return vec4<f32>(out_xy, out_z, clip_pos.w);
var out: VertexOutput;
out.position = vec4<f32>(out_xy, out_z, clip_pos.w);
#ifdef OPENGL_WORKAROUND
out.normalised_depth = 0.5 + 0.5 * (out_z / clip_pos.w);
#endif
return out;
}

View File

@ -56,6 +56,7 @@ impl PipelineKey {
depth_mode_int, set_depth_mode_int: 12, 11;
pub offset_zero, set_offset_zero: 13;
pub hdr_format, set_hdr_format: 14;
pub opengl_workaround, set_opengl_workaround: 15;
}
pub(crate) fn new() -> Self {
@ -129,6 +130,11 @@ impl PipelineKey {
self.set_hdr_format(hdr_format);
self
}
pub(crate) fn with_opengl_workaround(mut self, opengl_workaround: bool) -> Self {
self.set_opengl_workaround(opengl_workaround);
self
}
}
#[derive(Resource)]
@ -294,6 +300,11 @@ impl SpecializedMeshPipeline for OutlinePipeline {
bind_layouts.push(self.outline_volume_bind_group_layout.clone());
}
}
if key.opengl_workaround() {
let val = ShaderDefVal::from("OPENGL_WORKAROUND");
vertex_defs.push(val.clone());
fragment_defs.push(val);
}
let buffers = vec![mesh_layout.get_layout(&buffer_attrs)?];
Ok(RenderPipelineDescriptor {
vertex: VertexState {