Fix meshlet interactions with regular shading passes (#13816)

* Fixes https://github.com/bevyengine/bevy/issues/13813
* Fixes https://github.com/bevyengine/bevy/issues/13810

Tested a combined scene with both regular meshes and meshlet meshes
with:
* Regular forward setup
* Forward + normal/motion vector prepasses
* Deferred (with depth prepass since that's required) 
* Deferred + depth/normal/motion vector prepasses

Still broken:
* Using meshlet meshes rendering in deferred and regular meshes
rendering in forward + depth/normal prepass. I don't know how to fix
this at the moment, so for now I've just add instructions to not mix
them.
This commit is contained in:
JMS55 2024-06-21 12:06:08 -07:00 committed by François
parent 073db8cf36
commit b56a693c34
No known key found for this signature in database
5 changed files with 32 additions and 18 deletions

View file

@ -122,17 +122,17 @@ impl ViewNode for DeferredGBufferPrepassNode {
let view_entity = graph.view_entity();
render_context.add_command_buffer_generation_task(move |render_device| {
#[cfg(feature = "trace")]
let _deferred_span = info_span!("deferred").entered();
let _deferred_span = info_span!("deferred_prepass").entered();
// Command encoder setup
let mut command_encoder =
render_device.create_command_encoder(&CommandEncoderDescriptor {
label: Some("deferred_command_encoder"),
label: Some("deferred_prepass_command_encoder"),
});
// Render pass setup
let render_pass = command_encoder.begin_render_pass(&RenderPassDescriptor {
label: Some("deferred"),
label: Some("deferred_prepass"),
color_attachments: &color_attachments,
depth_stencil_attachment,
timestamp_writes: None,
@ -148,20 +148,20 @@ impl ViewNode for DeferredGBufferPrepassNode {
|| !opaque_deferred_phase.unbatchable_keys.is_empty()
{
#[cfg(feature = "trace")]
let _opaque_prepass_span = info_span!("opaque_deferred").entered();
let _opaque_prepass_span = info_span!("opaque_deferred_prepass").entered();
opaque_deferred_phase.render(&mut render_pass, world, view_entity);
}
// Alpha masked draws
if !alpha_mask_deferred_phase.is_empty() {
#[cfg(feature = "trace")]
let _alpha_mask_deferred_span = info_span!("alpha_mask_deferred").entered();
let _alpha_mask_deferred_span = info_span!("alpha_mask_deferred_prepass").entered();
alpha_mask_deferred_phase.render(&mut render_pass, world, view_entity);
}
drop(render_pass);
// Copy prepass depth to the main depth texture
// After rendering to the view depth texture, copy it to the prepass depth texture
if let Some(prepass_depth_texture) = &view_prepass_textures.depth {
command_encoder.copy_texture_to_texture(
view_depth_texture.texture.as_image_copy(),

View file

@ -162,7 +162,7 @@ impl ViewNode for PrepassNode {
pass_span.end(&mut render_pass);
drop(render_pass);
// Copy prepass depth to the main depth texture if deferred isn't going to
// After rendering to the view depth texture, copy it to the prepass depth texture if deferred isn't going to
if deferred_prepass.is_none() {
if let Some(prepass_depth_texture) = &view_prepass_textures.depth {
command_encoder.copy_texture_to_texture(

View file

@ -10,8 +10,13 @@ use crate::{
MeshViewBindGroup, PrepassViewBindGroup, ViewFogUniformOffset, ViewLightProbesUniformOffset,
ViewLightsUniformOffset, ViewScreenSpaceReflectionsUniformOffset,
};
use bevy_core_pipeline::prepass::{PreviousViewUniformOffset, ViewPrepassTextures};
use bevy_ecs::{query::QueryItem, world::World};
use bevy_core_pipeline::prepass::{
MotionVectorPrepass, PreviousViewUniformOffset, ViewPrepassTextures,
};
use bevy_ecs::{
query::{Has, QueryItem},
world::World,
};
use bevy_render::{
camera::ExtractedCamera,
render_graph::{NodeRunError, RenderGraphContext, ViewNode},
@ -138,7 +143,8 @@ impl ViewNode for MeshletPrepassNode {
&'static ExtractedCamera,
&'static ViewPrepassTextures,
&'static ViewUniformOffset,
Option<&'static PreviousViewUniformOffset>,
&'static PreviousViewUniformOffset,
Has<MotionVectorPrepass>,
&'static MeshletViewMaterialsPrepass,
&'static MeshletViewBindGroups,
&'static MeshletViewResources,
@ -153,6 +159,7 @@ impl ViewNode for MeshletPrepassNode {
view_prepass_textures,
view_uniform_offset,
previous_view_uniform_offset,
view_has_motion_vector_prepass,
meshlet_view_materials,
meshlet_view_bind_groups,
meshlet_view_resources,
@ -212,7 +219,7 @@ impl ViewNode for MeshletPrepassNode {
render_pass.set_camera_viewport(viewport);
}
if let Some(previous_view_uniform_offset) = previous_view_uniform_offset {
if view_has_motion_vector_prepass {
render_pass.set_bind_group(
0,
prepass_view_bind_group.motion_vectors.as_ref().unwrap(),
@ -259,7 +266,8 @@ impl ViewNode for MeshletDeferredGBufferPrepassNode {
&'static ExtractedCamera,
&'static ViewPrepassTextures,
&'static ViewUniformOffset,
Option<&'static PreviousViewUniformOffset>,
&'static PreviousViewUniformOffset,
Has<MotionVectorPrepass>,
&'static MeshletViewMaterialsDeferredGBufferPrepass,
&'static MeshletViewBindGroups,
&'static MeshletViewResources,
@ -274,6 +282,7 @@ impl ViewNode for MeshletDeferredGBufferPrepassNode {
view_prepass_textures,
view_uniform_offset,
previous_view_uniform_offset,
view_has_motion_vector_prepass,
meshlet_view_materials,
meshlet_view_bind_groups,
meshlet_view_resources,
@ -338,7 +347,7 @@ impl ViewNode for MeshletDeferredGBufferPrepassNode {
render_pass.set_camera_viewport(viewport);
}
if let Some(previous_view_uniform_offset) = previous_view_uniform_offset {
if view_has_motion_vector_prepass {
render_pass.set_bind_group(
0,
prepass_view_bind_group.motion_vectors.as_ref().unwrap(),

View file

@ -142,7 +142,8 @@ pub fn prepare_material_meshlet_meshes_main_opaque_pass<M: Material>(
continue;
};
if material.properties.alpha_mode != AlphaMode::Opaque
if material.properties.render_method != OpaqueRendererMethod::Forward
|| material.properties.alpha_mode != AlphaMode::Opaque
|| material.properties.reads_view_transmission_texture
{
continue;

View file

@ -109,6 +109,10 @@ const MESHLET_MESH_MATERIAL_SHADER_HANDLE: Handle<Shader> =
///
/// This plugin does not work on WASM.
///
/// Mixing forward+prepass and deferred rendering for opaque materials is not currently supported when using this plugin.
/// You must use one or the other by setting [`crate::DefaultOpaqueRendererMethod`].
/// Do not override [`crate::Material::opaque_render_method`] for any material when using this plugin.
///
/// ![A render of the Stanford dragon as a `MeshletMesh`](https://raw.githubusercontent.com/bevyengine/bevy/main/crates/bevy_pbr/src/meshlet/meshlet_preview.png)
pub struct MeshletPlugin;
@ -206,18 +210,18 @@ impl Plugin for MeshletPlugin {
.add_render_graph_edges(
Core3d,
(
// TODO: Meshlet VisibilityBufferRaster should be after main pass when not using depth prepass
// Non-meshlet shading passes _must_ come before meshlet shading passes
NodePbr::ShadowPass,
Node3d::Prepass,
Node3d::DeferredPrepass,
NodeMeshlet::VisibilityBufferRasterPass,
NodeMeshlet::Prepass,
Node3d::Prepass,
NodeMeshlet::DeferredPrepass,
Node3d::DeferredPrepass,
Node3d::CopyDeferredLightingId,
Node3d::EndPrepasses,
Node3d::StartMainPass,
Node3d::MainOpaquePass,
NodeMeshlet::MainOpaquePass,
Node3d::MainOpaquePass,
Node3d::EndMainPass,
),
)