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" bitfield = "0.14"
interpolation = "0.2" interpolation = "0.2"
thiserror = "1.0" thiserror = "1.0"
wgpu-types = "0.15"
[dev-dependencies] [dev-dependencies]
bevy = { version = "0.10", default-features = false, features = [ 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_asset::RenderAssets;
use bevy::render::render_phase::{DrawFunctions, RenderPhase, SetItemPipeline}; use bevy::render::render_phase::{DrawFunctions, RenderPhase, SetItemPipeline};
use bevy::render::render_resource::{PipelineCache, SpecializedMeshPipelines}; use bevy::render::render_resource::{PipelineCache, SpecializedMeshPipelines};
use bevy::render::renderer::RenderAdapterInfo;
use bevy::render::view::{ExtractedView, RenderLayers}; use bevy::render::view::{ExtractedView, RenderLayers};
use wgpu_types::Backend;
use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline}; use crate::node::{OpaqueOutline, StencilOutline, TransparentOutline};
use crate::pipeline::{OutlinePipeline, PassType, PipelineKey}; use crate::pipeline::{OutlinePipeline, PassType, PipelineKey};
@ -32,6 +34,7 @@ pub(crate) fn queue_outline_stencil_mesh(
mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>, mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>,
pipeline_cache: Res<PipelineCache>, pipeline_cache: Res<PipelineCache>,
render_meshes: Res<RenderAssets<Mesh>>, render_meshes: Res<RenderAssets<Mesh>>,
adapter_info: Res<RenderAdapterInfo>,
material_meshes: Query<( material_meshes: Query<(
Entity, Entity,
&Handle<Mesh>, &Handle<Mesh>,
@ -52,7 +55,8 @@ pub(crate) fn queue_outline_stencil_mesh(
let base_key = PipelineKey::new() let base_key = PipelineKey::new()
.with_msaa(*msaa) .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() { for (view, mut stencil_phase, view_mask) in views.iter_mut() {
let rangefinder = view.rangefinder3d(); let rangefinder = view.rangefinder3d();
@ -105,6 +109,7 @@ pub(crate) fn queue_outline_volume_mesh(
mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>, mut pipelines: ResMut<SpecializedMeshPipelines<OutlinePipeline>>,
pipeline_cache: Res<PipelineCache>, pipeline_cache: Res<PipelineCache>,
render_meshes: Res<RenderAssets<Mesh>>, render_meshes: Res<RenderAssets<Mesh>>,
adapter_info: Res<RenderAdapterInfo>,
material_meshes: Query<( material_meshes: Query<(
Entity, Entity,
&Handle<Mesh>, &Handle<Mesh>,
@ -129,7 +134,9 @@ pub(crate) fn queue_outline_volume_mesh(
.get_id::<DrawOutline>() .get_id::<DrawOutline>()
.unwrap(); .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() { for (view, mut opaque_phase, mut transparent_phase, view_mask) in views.iter_mut() {
let view_mask = view_mask.copied().unwrap_or_default(); 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 { struct OutlineFragmentUniform {
@align(16) @align(16)
colour: vec4<f32>, colour: vec4<f32>,
}; };
#ifdef VOLUME
@group(3) @binding(1) @group(3) @binding(1)
var<uniform> fstage: OutlineFragmentUniform; var<uniform> fstage: OutlineFragmentUniform;
@fragment
fn fragment() -> @location(0) vec4<f32> {
return fstage.colour;
}
#else
// Stencil
@fragment
fn fragment() {
return;
}
#endif #endif
@fragment
#ifdef OPENGL_WORKAROUND
fn fragment(@location(0) normalised_depth: f32) -> FragmentOutput {
#else
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 #endif
}; };
struct VertexOutput {
@builtin(position) position: vec4<f32>,
#ifdef OPENGL_WORKAROUND
@location(0) normalised_depth: f32,
#endif
};
struct OutlineViewUniform { struct OutlineViewUniform {
@align(16) @align(16)
scale: vec2<f32>, scale: vec2<f32>,
@ -53,7 +60,7 @@ fn model_origin_z(plane: vec3<f32>, view_proj: mat4x4<f32>) -> f32 {
} }
@vertex @vertex
fn vertex(vertex: VertexInput) -> @builtin(position) vec4<f32> { fn vertex(vertex: VertexInput) -> VertexOutput {
#ifdef SKINNED #ifdef SKINNED
let model = skin_model(vertex.joint_indexes, vertex.joint_weights); let model = skin_model(vertex.joint_indexes, vertex.joint_weights);
#else #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 ndc_delta = vstage.offset * normalize(clip_norm.xy) * view_uniform.scale * clip_pos.w;
let out_xy = clip_pos.xy + ndc_delta; let out_xy = clip_pos.xy + ndc_delta;
#endif #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; depth_mode_int, set_depth_mode_int: 12, 11;
pub offset_zero, set_offset_zero: 13; pub offset_zero, set_offset_zero: 13;
pub hdr_format, set_hdr_format: 14; pub hdr_format, set_hdr_format: 14;
pub opengl_workaround, set_opengl_workaround: 15;
} }
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
@ -129,6 +130,11 @@ impl PipelineKey {
self.set_hdr_format(hdr_format); self.set_hdr_format(hdr_format);
self self
} }
pub(crate) fn with_opengl_workaround(mut self, opengl_workaround: bool) -> Self {
self.set_opengl_workaround(opengl_workaround);
self
}
} }
#[derive(Resource)] #[derive(Resource)]
@ -294,6 +300,11 @@ impl SpecializedMeshPipeline for OutlinePipeline {
bind_layouts.push(self.outline_volume_bind_group_layout.clone()); 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)?]; let buffers = vec![mesh_layout.get_layout(&buffer_attrs)?];
Ok(RenderPipelineDescriptor { Ok(RenderPipelineDescriptor {
vertex: VertexState { vertex: VertexState {