mirror of
https://github.com/bevyengine/bevy
synced 2024-12-18 17:13:10 +00:00
Native unclipped depth on supported platforms (#16095)
# Objective - Fixes #16078 ## Solution - Rename things to clarify that we _want_ unclipped depth for directional light shadow views, and need some way of disabling the GPU's builtin depth clipping - Use DEPTH_CLIP_CONTROL instead of the fragment shader emulation on supported platforms - Pass only the clip position depth instead of the whole clip position between vertex->fragment shader (no idea if this helps performance or not, compiler might optimize it anyways) - Meshlets - HW raster always uses DEPTH_CLIP_CONTROL since it targets a more limited set of platforms - SW raster was not handling DEPTH_CLAMP_ORTHO correctly, it ended up pretty much doing nothing. - This PR made me realize that SW raster technically should have depth clipping for all views that are not directional light shadows, but I decided not to bother writing it. I'm not sure that it ever matters in practice. If proven otherwise, I can add it. ## Testing - Did you test these changes? If so, how? - Lighting example. Both opaque (no fragment shader) and alpha masked geometry (fragment shader emulation) are working with depth_clip_control, and both work when it's turned off. Also tested meshlet example. - Are there any parts that need more testing? - Performance. I can't figure out a good test scene. - How can other people (reviewers) test your changes? Is there anything specific they need to know? - Toggle depth_clip_control_supported in prepass/mod.rs line 323 to turn this PR on or off. - If relevant, what platforms did you test these changes on, and are there any important ones you can't test? - Native --- ## Migration Guide - `MeshPipelineKey::DEPTH_CLAMP_ORTHO` is now `MeshPipelineKey::UNCLIPPED_DEPTH_ORTHO` - The `DEPTH_CLAMP_ORTHO` shaderdef has been renamed to `UNCLIPPED_DEPTH_ORTHO_EMULATION` - `clip_position_unclamped: vec4<f32>` is now `unclipped_depth: f32`
This commit is contained in:
parent
f375422ddd
commit
d221665386
11 changed files with 60 additions and 105 deletions
|
@ -142,6 +142,7 @@ impl MeshletPlugin {
|
||||||
WgpuFeatures::SHADER_INT64_ATOMIC_MIN_MAX
|
WgpuFeatures::SHADER_INT64_ATOMIC_MIN_MAX
|
||||||
| WgpuFeatures::SHADER_INT64
|
| WgpuFeatures::SHADER_INT64
|
||||||
| WgpuFeatures::SUBGROUP
|
| WgpuFeatures::SUBGROUP
|
||||||
|
| WgpuFeatures::DEPTH_CLIP_CONTROL
|
||||||
| WgpuFeatures::PUSH_CONSTANTS
|
| WgpuFeatures::PUSH_CONSTANTS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,10 +34,9 @@ pub struct MeshletPipelines {
|
||||||
downsample_depth_second_shadow_view: CachedComputePipelineId,
|
downsample_depth_second_shadow_view: CachedComputePipelineId,
|
||||||
visibility_buffer_software_raster: CachedComputePipelineId,
|
visibility_buffer_software_raster: CachedComputePipelineId,
|
||||||
visibility_buffer_software_raster_depth_only: CachedComputePipelineId,
|
visibility_buffer_software_raster_depth_only: CachedComputePipelineId,
|
||||||
visibility_buffer_software_raster_depth_only_clamp_ortho: CachedComputePipelineId,
|
|
||||||
visibility_buffer_hardware_raster: CachedRenderPipelineId,
|
visibility_buffer_hardware_raster: CachedRenderPipelineId,
|
||||||
visibility_buffer_hardware_raster_depth_only: CachedRenderPipelineId,
|
visibility_buffer_hardware_raster_depth_only: CachedRenderPipelineId,
|
||||||
visibility_buffer_hardware_raster_depth_only_clamp_ortho: CachedRenderPipelineId,
|
visibility_buffer_hardware_raster_depth_only_unclipped: CachedRenderPipelineId,
|
||||||
resolve_depth: CachedRenderPipelineId,
|
resolve_depth: CachedRenderPipelineId,
|
||||||
resolve_depth_shadow_view: CachedRenderPipelineId,
|
resolve_depth_shadow_view: CachedRenderPipelineId,
|
||||||
resolve_material_depth: CachedRenderPipelineId,
|
resolve_material_depth: CachedRenderPipelineId,
|
||||||
|
@ -215,29 +214,6 @@ impl FromWorld for MeshletPipelines {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
visibility_buffer_software_raster_depth_only_clamp_ortho: pipeline_cache
|
|
||||||
.queue_compute_pipeline(ComputePipelineDescriptor {
|
|
||||||
label: Some(
|
|
||||||
"meshlet_visibility_buffer_software_raster_depth_only_clamp_ortho_pipeline"
|
|
||||||
.into(),
|
|
||||||
),
|
|
||||||
layout: vec![visibility_buffer_raster_layout.clone()],
|
|
||||||
push_constant_ranges: vec![],
|
|
||||||
shader: MESHLET_VISIBILITY_BUFFER_SOFTWARE_RASTER_SHADER_HANDLE,
|
|
||||||
shader_defs: vec![
|
|
||||||
"MESHLET_VISIBILITY_BUFFER_RASTER_PASS".into(),
|
|
||||||
"DEPTH_CLAMP_ORTHO".into(),
|
|
||||||
if remap_1d_to_2d_dispatch_layout.is_some() {
|
|
||||||
"MESHLET_2D_DISPATCH"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
],
|
|
||||||
entry_point: "rasterize_cluster".into(),
|
|
||||||
zero_initialize_workgroup_memory: false,
|
|
||||||
}),
|
|
||||||
|
|
||||||
visibility_buffer_hardware_raster: pipeline_cache.queue_render_pipeline(
|
visibility_buffer_hardware_raster: pipeline_cache.queue_render_pipeline(
|
||||||
RenderPipelineDescriptor {
|
RenderPipelineDescriptor {
|
||||||
label: Some("meshlet_visibility_buffer_hardware_raster_pipeline".into()),
|
label: Some("meshlet_visibility_buffer_hardware_raster_pipeline".into()),
|
||||||
|
@ -324,10 +300,10 @@ impl FromWorld for MeshletPipelines {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
visibility_buffer_hardware_raster_depth_only_clamp_ortho: pipeline_cache
|
visibility_buffer_hardware_raster_depth_only_unclipped: pipeline_cache
|
||||||
.queue_render_pipeline(RenderPipelineDescriptor {
|
.queue_render_pipeline(RenderPipelineDescriptor {
|
||||||
label: Some(
|
label: Some(
|
||||||
"meshlet_visibility_buffer_hardware_raster_depth_only_clamp_ortho_pipeline"
|
"meshlet_visibility_buffer_hardware_raster_depth_only_unclipped_pipeline"
|
||||||
.into(),
|
.into(),
|
||||||
),
|
),
|
||||||
layout: vec![visibility_buffer_raster_layout],
|
layout: vec![visibility_buffer_raster_layout],
|
||||||
|
@ -337,10 +313,7 @@ impl FromWorld for MeshletPipelines {
|
||||||
}],
|
}],
|
||||||
vertex: VertexState {
|
vertex: VertexState {
|
||||||
shader: MESHLET_VISIBILITY_BUFFER_HARDWARE_RASTER_SHADER_HANDLE,
|
shader: MESHLET_VISIBILITY_BUFFER_HARDWARE_RASTER_SHADER_HANDLE,
|
||||||
shader_defs: vec![
|
shader_defs: vec!["MESHLET_VISIBILITY_BUFFER_RASTER_PASS".into()],
|
||||||
"MESHLET_VISIBILITY_BUFFER_RASTER_PASS".into(),
|
|
||||||
"DEPTH_CLAMP_ORTHO".into(),
|
|
||||||
],
|
|
||||||
entry_point: "vertex".into(),
|
entry_point: "vertex".into(),
|
||||||
buffers: vec![],
|
buffers: vec![],
|
||||||
},
|
},
|
||||||
|
@ -349,7 +322,7 @@ impl FromWorld for MeshletPipelines {
|
||||||
strip_index_format: None,
|
strip_index_format: None,
|
||||||
front_face: FrontFace::Ccw,
|
front_face: FrontFace::Ccw,
|
||||||
cull_mode: Some(Face::Back),
|
cull_mode: Some(Face::Back),
|
||||||
unclipped_depth: false,
|
unclipped_depth: true,
|
||||||
polygon_mode: PolygonMode::Fill,
|
polygon_mode: PolygonMode::Fill,
|
||||||
conservative: false,
|
conservative: false,
|
||||||
},
|
},
|
||||||
|
@ -357,10 +330,7 @@ impl FromWorld for MeshletPipelines {
|
||||||
multisample: MultisampleState::default(),
|
multisample: MultisampleState::default(),
|
||||||
fragment: Some(FragmentState {
|
fragment: Some(FragmentState {
|
||||||
shader: MESHLET_VISIBILITY_BUFFER_HARDWARE_RASTER_SHADER_HANDLE,
|
shader: MESHLET_VISIBILITY_BUFFER_HARDWARE_RASTER_SHADER_HANDLE,
|
||||||
shader_defs: vec![
|
shader_defs: vec!["MESHLET_VISIBILITY_BUFFER_RASTER_PASS".into()],
|
||||||
"MESHLET_VISIBILITY_BUFFER_RASTER_PASS".into(),
|
|
||||||
"DEPTH_CLAMP_ORTHO".into(),
|
|
||||||
],
|
|
||||||
entry_point: "fragment".into(),
|
entry_point: "fragment".into(),
|
||||||
targets: vec![Some(ColorTargetState {
|
targets: vec![Some(ColorTargetState {
|
||||||
format: TextureFormat::R8Uint,
|
format: TextureFormat::R8Uint,
|
||||||
|
@ -484,7 +454,6 @@ impl MeshletPipelines {
|
||||||
&ComputePipeline,
|
&ComputePipeline,
|
||||||
&ComputePipeline,
|
&ComputePipeline,
|
||||||
&ComputePipeline,
|
&ComputePipeline,
|
||||||
&ComputePipeline,
|
|
||||||
&RenderPipeline,
|
&RenderPipeline,
|
||||||
&RenderPipeline,
|
&RenderPipeline,
|
||||||
&RenderPipeline,
|
&RenderPipeline,
|
||||||
|
@ -506,14 +475,11 @@ impl MeshletPipelines {
|
||||||
pipeline_cache.get_compute_pipeline(pipeline.visibility_buffer_software_raster)?,
|
pipeline_cache.get_compute_pipeline(pipeline.visibility_buffer_software_raster)?,
|
||||||
pipeline_cache
|
pipeline_cache
|
||||||
.get_compute_pipeline(pipeline.visibility_buffer_software_raster_depth_only)?,
|
.get_compute_pipeline(pipeline.visibility_buffer_software_raster_depth_only)?,
|
||||||
pipeline_cache.get_compute_pipeline(
|
|
||||||
pipeline.visibility_buffer_software_raster_depth_only_clamp_ortho,
|
|
||||||
)?,
|
|
||||||
pipeline_cache.get_render_pipeline(pipeline.visibility_buffer_hardware_raster)?,
|
pipeline_cache.get_render_pipeline(pipeline.visibility_buffer_hardware_raster)?,
|
||||||
pipeline_cache
|
pipeline_cache
|
||||||
.get_render_pipeline(pipeline.visibility_buffer_hardware_raster_depth_only)?,
|
.get_render_pipeline(pipeline.visibility_buffer_hardware_raster_depth_only)?,
|
||||||
pipeline_cache.get_render_pipeline(
|
pipeline_cache.get_render_pipeline(
|
||||||
pipeline.visibility_buffer_hardware_raster_depth_only_clamp_ortho,
|
pipeline.visibility_buffer_hardware_raster_depth_only_unclipped,
|
||||||
)?,
|
)?,
|
||||||
pipeline_cache.get_render_pipeline(pipeline.resolve_depth)?,
|
pipeline_cache.get_render_pipeline(pipeline.resolve_depth)?,
|
||||||
pipeline_cache.get_render_pipeline(pipeline.resolve_depth_shadow_view)?,
|
pipeline_cache.get_render_pipeline(pipeline.resolve_depth_shadow_view)?,
|
||||||
|
|
|
@ -23,9 +23,6 @@ struct VertexOutput {
|
||||||
#ifdef MESHLET_VISIBILITY_BUFFER_RASTER_PASS_OUTPUT
|
#ifdef MESHLET_VISIBILITY_BUFFER_RASTER_PASS_OUTPUT
|
||||||
@location(0) @interpolate(flat) packed_ids: u32,
|
@location(0) @interpolate(flat) packed_ids: u32,
|
||||||
#endif
|
#endif
|
||||||
#ifdef DEPTH_CLAMP_ORTHO
|
|
||||||
@location(0) unclamped_clip_depth: f32,
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
|
@ -45,19 +42,12 @@ fn vertex(@builtin(instance_index) instance_index: u32, @builtin(vertex_index) v
|
||||||
let vertex_position = get_meshlet_vertex_position(&meshlet, vertex_id);
|
let vertex_position = get_meshlet_vertex_position(&meshlet, vertex_id);
|
||||||
let world_from_local = affine3_to_square(instance_uniform.world_from_local);
|
let world_from_local = affine3_to_square(instance_uniform.world_from_local);
|
||||||
let world_position = mesh_position_local_to_world(world_from_local, vec4(vertex_position, 1.0));
|
let world_position = mesh_position_local_to_world(world_from_local, vec4(vertex_position, 1.0));
|
||||||
var clip_position = view.clip_from_world * vec4(world_position.xyz, 1.0);
|
let clip_position = view.clip_from_world * vec4(world_position.xyz, 1.0);
|
||||||
#ifdef DEPTH_CLAMP_ORTHO
|
|
||||||
let unclamped_clip_depth = clip_position.z;
|
|
||||||
clip_position.z = min(clip_position.z, 1.0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return VertexOutput(
|
return VertexOutput(
|
||||||
clip_position,
|
clip_position,
|
||||||
#ifdef MESHLET_VISIBILITY_BUFFER_RASTER_PASS_OUTPUT
|
#ifdef MESHLET_VISIBILITY_BUFFER_RASTER_PASS_OUTPUT
|
||||||
(cluster_id << 7u) | triangle_id,
|
(cluster_id << 7u) | triangle_id,
|
||||||
#endif
|
|
||||||
#ifdef DEPTH_CLAMP_ORTHO
|
|
||||||
unclamped_clip_depth,
|
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -70,9 +60,6 @@ fn fragment(vertex_output: VertexOutput) {
|
||||||
let depth = bitcast<u32>(vertex_output.position.z);
|
let depth = bitcast<u32>(vertex_output.position.z);
|
||||||
let visibility = (u64(depth) << 32u) | u64(vertex_output.packed_ids);
|
let visibility = (u64(depth) << 32u) | u64(vertex_output.packed_ids);
|
||||||
atomicMax(&meshlet_visibility_buffer[frag_coord_1d], visibility);
|
atomicMax(&meshlet_visibility_buffer[frag_coord_1d], visibility);
|
||||||
#else ifdef DEPTH_CLAMP_ORTHO
|
|
||||||
let depth = bitcast<u32>(vertex_output.unclamped_clip_depth);
|
|
||||||
atomicMax(&meshlet_visibility_buffer[frag_coord_1d], depth);
|
|
||||||
#else
|
#else
|
||||||
let depth = bitcast<u32>(vertex_output.position.z);
|
let depth = bitcast<u32>(vertex_output.position.z);
|
||||||
atomicMax(&meshlet_visibility_buffer[frag_coord_1d], depth);
|
atomicMax(&meshlet_visibility_buffer[frag_coord_1d], depth);
|
||||||
|
@ -84,9 +71,6 @@ fn dummy_vertex() -> VertexOutput {
|
||||||
vec4(divide(0.0, 0.0)), // NaN vertex position
|
vec4(divide(0.0, 0.0)), // NaN vertex position
|
||||||
#ifdef MESHLET_VISIBILITY_BUFFER_RASTER_PASS_OUTPUT
|
#ifdef MESHLET_VISIBILITY_BUFFER_RASTER_PASS_OUTPUT
|
||||||
0u,
|
0u,
|
||||||
#endif
|
|
||||||
#ifdef DEPTH_CLAMP_ORTHO
|
|
||||||
0.0,
|
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,10 +85,9 @@ impl Node for MeshletVisibilityBufferRasterPassNode {
|
||||||
downsample_depth_second_shadow_view_pipeline,
|
downsample_depth_second_shadow_view_pipeline,
|
||||||
visibility_buffer_software_raster_pipeline,
|
visibility_buffer_software_raster_pipeline,
|
||||||
visibility_buffer_software_raster_depth_only_pipeline,
|
visibility_buffer_software_raster_depth_only_pipeline,
|
||||||
visibility_buffer_software_raster_depth_only_clamp_ortho,
|
|
||||||
visibility_buffer_hardware_raster_pipeline,
|
visibility_buffer_hardware_raster_pipeline,
|
||||||
visibility_buffer_hardware_raster_depth_only_pipeline,
|
visibility_buffer_hardware_raster_depth_only_pipeline,
|
||||||
visibility_buffer_hardware_raster_depth_only_clamp_ortho,
|
visibility_buffer_hardware_raster_depth_only_unclipped_pipeline,
|
||||||
resolve_depth_pipeline,
|
resolve_depth_pipeline,
|
||||||
resolve_depth_shadow_view_pipeline,
|
resolve_depth_shadow_view_pipeline,
|
||||||
resolve_material_depth_pipeline,
|
resolve_material_depth_pipeline,
|
||||||
|
@ -223,18 +222,11 @@ impl Node for MeshletVisibilityBufferRasterPassNode {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let (
|
let shadow_visibility_buffer_hardware_raster_pipeline =
|
||||||
shadow_visibility_buffer_software_raster_pipeline,
|
if let LightEntity::Directional { .. } = light_type {
|
||||||
shadow_visibility_buffer_hardware_raster_pipeline,
|
visibility_buffer_hardware_raster_depth_only_unclipped_pipeline
|
||||||
) = match light_type {
|
} else {
|
||||||
LightEntity::Directional { .. } => (
|
visibility_buffer_hardware_raster_depth_only_pipeline
|
||||||
visibility_buffer_software_raster_depth_only_clamp_ortho,
|
|
||||||
visibility_buffer_hardware_raster_depth_only_clamp_ortho,
|
|
||||||
),
|
|
||||||
_ => (
|
|
||||||
visibility_buffer_software_raster_depth_only_pipeline,
|
|
||||||
visibility_buffer_hardware_raster_depth_only_pipeline,
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render_context.command_encoder().push_debug_group(&format!(
|
render_context.command_encoder().push_debug_group(&format!(
|
||||||
|
@ -270,7 +262,7 @@ impl Node for MeshletVisibilityBufferRasterPassNode {
|
||||||
&meshlet_view_resources.dummy_render_target.default_view,
|
&meshlet_view_resources.dummy_render_target.default_view,
|
||||||
meshlet_view_bind_groups,
|
meshlet_view_bind_groups,
|
||||||
view_offset,
|
view_offset,
|
||||||
shadow_visibility_buffer_software_raster_pipeline,
|
visibility_buffer_software_raster_depth_only_pipeline,
|
||||||
shadow_visibility_buffer_hardware_raster_pipeline,
|
shadow_visibility_buffer_hardware_raster_pipeline,
|
||||||
None,
|
None,
|
||||||
meshlet_view_resources.raster_cluster_rightmost_slot,
|
meshlet_view_resources.raster_cluster_rightmost_slot,
|
||||||
|
@ -306,7 +298,7 @@ impl Node for MeshletVisibilityBufferRasterPassNode {
|
||||||
&meshlet_view_resources.dummy_render_target.default_view,
|
&meshlet_view_resources.dummy_render_target.default_view,
|
||||||
meshlet_view_bind_groups,
|
meshlet_view_bind_groups,
|
||||||
view_offset,
|
view_offset,
|
||||||
shadow_visibility_buffer_software_raster_pipeline,
|
visibility_buffer_software_raster_depth_only_pipeline,
|
||||||
shadow_visibility_buffer_hardware_raster_pipeline,
|
shadow_visibility_buffer_hardware_raster_pipeline,
|
||||||
None,
|
None,
|
||||||
meshlet_view_resources.raster_cluster_rightmost_slot,
|
meshlet_view_resources.raster_cluster_rightmost_slot,
|
||||||
|
|
|
@ -57,10 +57,7 @@ fn rasterize_cluster(
|
||||||
// Project vertex to viewport space
|
// Project vertex to viewport space
|
||||||
let world_position = mesh_position_local_to_world(world_from_local, vec4(vertex_position, 1.0));
|
let world_position = mesh_position_local_to_world(world_from_local, vec4(vertex_position, 1.0));
|
||||||
let clip_position = view.clip_from_world * vec4(world_position.xyz, 1.0);
|
let clip_position = view.clip_from_world * vec4(world_position.xyz, 1.0);
|
||||||
var ndc_position = clip_position.xyz / clip_position.w;
|
let ndc_position = clip_position.xyz / clip_position.w;
|
||||||
#ifdef DEPTH_CLAMP_ORTHO
|
|
||||||
ndc_position.z = 1.0 / clip_position.z;
|
|
||||||
#endif
|
|
||||||
let viewport_position_xy = ndc_to_uv(ndc_position.xy) * view.viewport.zw;
|
let viewport_position_xy = ndc_to_uv(ndc_position.xy) * view.viewport.zw;
|
||||||
|
|
||||||
// Write vertex to workgroup shared memory
|
// Write vertex to workgroup shared memory
|
||||||
|
@ -176,9 +173,6 @@ fn write_visibility_buffer_pixel(x: f32, y: f32, z: f32, packed_ids: u32) {
|
||||||
let depth = bitcast<u32>(z);
|
let depth = bitcast<u32>(z);
|
||||||
let visibility = (u64(depth) << 32u) | u64(packed_ids);
|
let visibility = (u64(depth) << 32u) | u64(packed_ids);
|
||||||
atomicMax(&meshlet_visibility_buffer[frag_coord_1d], visibility);
|
atomicMax(&meshlet_visibility_buffer[frag_coord_1d], visibility);
|
||||||
#else ifdef DEPTH_CLAMP_ORTHO
|
|
||||||
let depth = bitcast<u32>(1.0 / z);
|
|
||||||
atomicMax(&meshlet_visibility_buffer[frag_coord_1d], depth);
|
|
||||||
#else
|
#else
|
||||||
let depth = bitcast<u32>(z);
|
let depth = bitcast<u32>(z);
|
||||||
atomicMax(&meshlet_visibility_buffer[frag_coord_1d], depth);
|
atomicMax(&meshlet_visibility_buffer[frag_coord_1d], depth);
|
||||||
|
|
|
@ -251,6 +251,7 @@ pub struct PrepassPipeline<M: Material> {
|
||||||
pub deferred_material_vertex_shader: Option<Handle<Shader>>,
|
pub deferred_material_vertex_shader: Option<Handle<Shader>>,
|
||||||
pub deferred_material_fragment_shader: Option<Handle<Shader>>,
|
pub deferred_material_fragment_shader: Option<Handle<Shader>>,
|
||||||
pub material_pipeline: MaterialPipeline<M>,
|
pub material_pipeline: MaterialPipeline<M>,
|
||||||
|
pub depth_clip_control_supported: bool,
|
||||||
_marker: PhantomData<M>,
|
_marker: PhantomData<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +290,10 @@ impl<M: Material> FromWorld for PrepassPipeline<M> {
|
||||||
|
|
||||||
let mesh_pipeline = world.resource::<MeshPipeline>();
|
let mesh_pipeline = world.resource::<MeshPipeline>();
|
||||||
|
|
||||||
|
let depth_clip_control_supported = render_device
|
||||||
|
.features()
|
||||||
|
.contains(WgpuFeatures::DEPTH_CLIP_CONTROL);
|
||||||
|
|
||||||
PrepassPipeline {
|
PrepassPipeline {
|
||||||
view_layout_motion_vectors,
|
view_layout_motion_vectors,
|
||||||
view_layout_no_motion_vectors,
|
view_layout_no_motion_vectors,
|
||||||
|
@ -315,6 +320,7 @@ impl<M: Material> FromWorld for PrepassPipeline<M> {
|
||||||
},
|
},
|
||||||
material_layout: M::bind_group_layout(render_device),
|
material_layout: M::bind_group_layout(render_device),
|
||||||
material_pipeline: world.resource::<MaterialPipeline<M>>().clone(),
|
material_pipeline: world.resource::<MaterialPipeline<M>>().clone(),
|
||||||
|
depth_clip_control_supported,
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -379,8 +385,14 @@ where
|
||||||
vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
|
vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if key.mesh_key.contains(MeshPipelineKey::DEPTH_CLAMP_ORTHO) {
|
// For directional light shadow map views, use unclipped depth via either the native GPU feature,
|
||||||
shader_defs.push("DEPTH_CLAMP_ORTHO".into());
|
// or emulated by setting depth in the fragment shader for GPUs that don't support it natively.
|
||||||
|
let emulate_unclipped_depth = key
|
||||||
|
.mesh_key
|
||||||
|
.contains(MeshPipelineKey::UNCLIPPED_DEPTH_ORTHO)
|
||||||
|
&& !self.depth_clip_control_supported;
|
||||||
|
if emulate_unclipped_depth {
|
||||||
|
shader_defs.push("UNCLIPPED_DEPTH_ORTHO_EMULATION".into());
|
||||||
// PERF: This line forces the "prepass fragment shader" to always run in
|
// PERF: This line forces the "prepass fragment shader" to always run in
|
||||||
// common scenarios like "directional light calculation". Doing so resolves
|
// common scenarios like "directional light calculation". Doing so resolves
|
||||||
// a pretty nasty depth clamping bug, but it also feels a bit excessive.
|
// a pretty nasty depth clamping bug, but it also feels a bit excessive.
|
||||||
|
@ -389,6 +401,10 @@ where
|
||||||
// https://github.com/bevyengine/bevy/pull/8877
|
// https://github.com/bevyengine/bevy/pull/8877
|
||||||
shader_defs.push("PREPASS_FRAGMENT".into());
|
shader_defs.push("PREPASS_FRAGMENT".into());
|
||||||
}
|
}
|
||||||
|
let unclipped_depth = key
|
||||||
|
.mesh_key
|
||||||
|
.contains(MeshPipelineKey::UNCLIPPED_DEPTH_ORTHO)
|
||||||
|
&& self.depth_clip_control_supported;
|
||||||
|
|
||||||
if layout.0.contains(Mesh::ATTRIBUTE_UV_0) {
|
if layout.0.contains(Mesh::ATTRIBUTE_UV_0) {
|
||||||
shader_defs.push("VERTEX_UVS".into());
|
shader_defs.push("VERTEX_UVS".into());
|
||||||
|
@ -488,10 +504,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// The fragment shader is only used when the normal prepass or motion vectors prepass
|
// The fragment shader is only used when the normal prepass or motion vectors prepass
|
||||||
// is enabled or the material uses alpha cutoff values and doesn't rely on the standard
|
// is enabled, the material uses alpha cutoff values and doesn't rely on the standard
|
||||||
// prepass shader or we are clamping the orthographic depth.
|
// prepass shader, or we are emulating unclipped depth in the fragment shader.
|
||||||
let fragment_required = !targets.is_empty()
|
let fragment_required = !targets.is_empty()
|
||||||
|| key.mesh_key.contains(MeshPipelineKey::DEPTH_CLAMP_ORTHO)
|
|| emulate_unclipped_depth
|
||||||
|| (key.mesh_key.contains(MeshPipelineKey::MAY_DISCARD)
|
|| (key.mesh_key.contains(MeshPipelineKey::MAY_DISCARD)
|
||||||
&& self.prepass_material_fragment_shader.is_some());
|
&& self.prepass_material_fragment_shader.is_some());
|
||||||
|
|
||||||
|
@ -544,7 +560,7 @@ where
|
||||||
strip_index_format: None,
|
strip_index_format: None,
|
||||||
front_face: FrontFace::Ccw,
|
front_face: FrontFace::Ccw,
|
||||||
cull_mode: None,
|
cull_mode: None,
|
||||||
unclipped_depth: false,
|
unclipped_depth,
|
||||||
polygon_mode: PolygonMode::Fill,
|
polygon_mode: PolygonMode::Fill,
|
||||||
conservative: false,
|
conservative: false,
|
||||||
},
|
},
|
||||||
|
|
|
@ -76,10 +76,10 @@ fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
|
||||||
|
|
||||||
out.world_position = mesh_functions::mesh_position_local_to_world(world_from_local, vec4<f32>(vertex.position, 1.0));
|
out.world_position = mesh_functions::mesh_position_local_to_world(world_from_local, vec4<f32>(vertex.position, 1.0));
|
||||||
out.position = position_world_to_clip(out.world_position.xyz);
|
out.position = position_world_to_clip(out.world_position.xyz);
|
||||||
#ifdef DEPTH_CLAMP_ORTHO
|
#ifdef UNCLIPPED_DEPTH_ORTHO_EMULATION
|
||||||
out.clip_position_unclamped = out.position;
|
out.unclipped_depth = out.position.z;
|
||||||
out.position.z = min(out.position.z, 1.0);
|
out.position.z = min(out.position.z, 1.0); // Clamp depth to avoid clipping
|
||||||
#endif // DEPTH_CLAMP_ORTHO
|
#endif // UNCLIPPED_DEPTH_ORTHO_EMULATION
|
||||||
|
|
||||||
#ifdef VERTEX_UVS_A
|
#ifdef VERTEX_UVS_A
|
||||||
out.uv = vertex.uv;
|
out.uv = vertex.uv;
|
||||||
|
@ -173,9 +173,9 @@ fn fragment(in: VertexOutput) -> FragmentOutput {
|
||||||
out.normal = vec4(in.world_normal * 0.5 + vec3(0.5), 1.0);
|
out.normal = vec4(in.world_normal * 0.5 + vec3(0.5), 1.0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEPTH_CLAMP_ORTHO
|
#ifdef UNCLIPPED_DEPTH_ORTHO_EMULATION
|
||||||
out.frag_depth = in.clip_position_unclamped.z;
|
out.frag_depth = in.unclipped_depth;
|
||||||
#endif // DEPTH_CLAMP_ORTHO
|
#endif // UNCLIPPED_DEPTH_ORTHO_EMULATION
|
||||||
|
|
||||||
#ifdef MOTION_VECTOR_PREPASS
|
#ifdef MOTION_VECTOR_PREPASS
|
||||||
let clip_position_t = view.unjittered_clip_from_world * in.world_position;
|
let clip_position_t = view.unjittered_clip_from_world * in.world_position;
|
||||||
|
|
|
@ -60,9 +60,9 @@ struct VertexOutput {
|
||||||
@location(5) previous_world_position: vec4<f32>,
|
@location(5) previous_world_position: vec4<f32>,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEPTH_CLAMP_ORTHO
|
#ifdef UNCLIPPED_DEPTH_ORTHO_EMULATION
|
||||||
@location(6) clip_position_unclamped: vec4<f32>,
|
@location(6) unclipped_depth: f32,
|
||||||
#endif // DEPTH_CLAMP_ORTHO
|
#endif // UNCLIPPED_DEPTH_ORTHO_EMULATION
|
||||||
#ifdef VERTEX_OUTPUT_INSTANCE_INDEX
|
#ifdef VERTEX_OUTPUT_INSTANCE_INDEX
|
||||||
@location(7) instance_index: u32,
|
@location(7) instance_index: u32,
|
||||||
#endif
|
#endif
|
||||||
|
@ -87,8 +87,8 @@ struct FragmentOutput {
|
||||||
@location(3) deferred_lighting_pass_id: u32,
|
@location(3) deferred_lighting_pass_id: u32,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEPTH_CLAMP_ORTHO
|
#ifdef UNCLIPPED_DEPTH_ORTHO_EMULATION
|
||||||
@builtin(frag_depth) frag_depth: f32,
|
@builtin(frag_depth) frag_depth: f32,
|
||||||
#endif // DEPTH_CLAMP_ORTHO
|
#endif // UNCLIPPED_DEPTH_ORTHO_EMULATION
|
||||||
}
|
}
|
||||||
#endif //PREPASS_FRAGMENT
|
#endif //PREPASS_FRAGMENT
|
||||||
|
|
|
@ -1554,7 +1554,7 @@ pub fn queue_shadows<M: Material>(
|
||||||
.expect("Failed to get spot light visible entities"),
|
.expect("Failed to get spot light visible entities"),
|
||||||
};
|
};
|
||||||
let mut light_key = MeshPipelineKey::DEPTH_PREPASS;
|
let mut light_key = MeshPipelineKey::DEPTH_PREPASS;
|
||||||
light_key.set(MeshPipelineKey::DEPTH_CLAMP_ORTHO, is_directional_light);
|
light_key.set(MeshPipelineKey::UNCLIPPED_DEPTH_ORTHO, is_directional_light);
|
||||||
|
|
||||||
// NOTE: Lights with shadow mapping disabled will have no visible entities
|
// NOTE: Lights with shadow mapping disabled will have no visible entities
|
||||||
// so no meshes will be queued
|
// so no meshes will be queued
|
||||||
|
|
|
@ -1489,7 +1489,9 @@ bitflags::bitflags! {
|
||||||
// See: https://www.khronos.org/opengl/wiki/Early_Fragment_Test
|
// See: https://www.khronos.org/opengl/wiki/Early_Fragment_Test
|
||||||
const ENVIRONMENT_MAP = 1 << 8;
|
const ENVIRONMENT_MAP = 1 << 8;
|
||||||
const SCREEN_SPACE_AMBIENT_OCCLUSION = 1 << 9;
|
const SCREEN_SPACE_AMBIENT_OCCLUSION = 1 << 9;
|
||||||
const DEPTH_CLAMP_ORTHO = 1 << 10;
|
const UNCLIPPED_DEPTH_ORTHO = 1 << 10; // Disables depth clipping for use with directional light shadow views
|
||||||
|
// Emulated via fragment shader depth on hardware that doesn't support it natively
|
||||||
|
// See: https://www.w3.org/TR/webgpu/#depth-clipping and https://therealmjp.github.io/posts/shadow-maps/#disabling-z-clipping
|
||||||
const TEMPORAL_JITTER = 1 << 11;
|
const TEMPORAL_JITTER = 1 << 11;
|
||||||
const READS_VIEW_TRANSMISSION_TEXTURE = 1 << 12;
|
const READS_VIEW_TRANSMISSION_TEXTURE = 1 << 12;
|
||||||
const LIGHTMAPPED = 1 << 13;
|
const LIGHTMAPPED = 1 << 13;
|
||||||
|
|
|
@ -32,9 +32,9 @@ fn fragment(
|
||||||
|
|
||||||
var out: prepass_io::FragmentOutput;
|
var out: prepass_io::FragmentOutput;
|
||||||
|
|
||||||
#ifdef DEPTH_CLAMP_ORTHO
|
#ifdef UNCLIPPED_DEPTH_ORTHO_EMULATION
|
||||||
out.frag_depth = in.clip_position_unclamped.z;
|
out.frag_depth = in.unclipped_depth;
|
||||||
#endif // DEPTH_CLAMP_ORTHO
|
#endif // UNCLIPPED_DEPTH_ORTHO_EMULATION
|
||||||
|
|
||||||
#ifdef NORMAL_PREPASS
|
#ifdef NORMAL_PREPASS
|
||||||
// NOTE: Unlit bit not set means == 0 is true, so the true case is if lit
|
// NOTE: Unlit bit not set means == 0 is true, so the true case is if lit
|
||||||
|
|
Loading…
Reference in a new issue