From 35032e05a305a2d1b73986bad03812bf7d05acad Mon Sep 17 00:00:00 2001 From: Robin KAY Date: Tue, 30 May 2023 21:51:13 +0100 Subject: [PATCH] Fix Z-fighting between overlay and stencil with OpenGL wgpu back-end. --- Cargo.toml | 1 + src/draw.rs | 11 +++++++++-- src/fragment.wgsl | 34 +++++++++++++++++++++------------- src/outline.wgsl | 16 ++++++++++++++-- src/pipeline.rs | 11 +++++++++++ 5 files changed, 56 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7b86779..d1b5d46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 = [ diff --git a/src/draw.rs b/src/draw.rs index a8fd63e..f409d72 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -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>, pipeline_cache: Res, render_meshes: Res>, + adapter_info: Res, material_meshes: Query<( Entity, &Handle, @@ -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>, pipeline_cache: Res, render_meshes: Res>, + adapter_info: Res, material_meshes: Query<( Entity, &Handle, @@ -129,7 +134,9 @@ pub(crate) fn queue_outline_volume_mesh( .get_id::() .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(); diff --git a/src/fragment.wgsl b/src/fragment.wgsl index 2f0de9a..4607f75 100644 --- a/src/fragment.wgsl +++ b/src/fragment.wgsl @@ -1,24 +1,32 @@ -#ifdef VOLUME +struct FragmentOutput { + @location(0) colour: vec4, +#ifdef OPENGL_WORKAROUND + @builtin(frag_depth) frag_depth: f32, +#endif +}; struct OutlineFragmentUniform { @align(16) colour: vec4, }; +#ifdef VOLUME @group(3) @binding(1) var fstage: OutlineFragmentUniform; +#endif @fragment -fn fragment() -> @location(0) vec4 { - return fstage.colour; -} - +#ifdef OPENGL_WORKAROUND +fn fragment(@location(0) normalised_depth: f32) -> FragmentOutput { #else -// Stencil - -@fragment -fn fragment() { - return; -} - -#endif \ No newline at end of file +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; +} \ No newline at end of file diff --git a/src/outline.wgsl b/src/outline.wgsl index fe8e031..61b5fe2 100644 --- a/src/outline.wgsl +++ b/src/outline.wgsl @@ -12,6 +12,13 @@ struct VertexInput { #endif }; +struct VertexOutput { + @builtin(position) position: vec4, +#ifdef OPENGL_WORKAROUND + @location(0) normalised_depth: f32, +#endif +}; + struct OutlineViewUniform { @align(16) scale: vec2, @@ -53,7 +60,7 @@ fn model_origin_z(plane: vec3, view_proj: mat4x4) -> f32 { } @vertex -fn vertex(vertex: VertexInput) -> @builtin(position) vec4 { +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 { 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(out_xy, out_z, clip_pos.w); + var out: VertexOutput; + out.position = vec4(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; } diff --git a/src/pipeline.rs b/src/pipeline.rs index 828d32a..a64c573 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -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 {