Use the prepass normal texture in main pass when possible (#8231)

# Objective

- We support enabling a normal prepass, but the main pass never actually
uses it and recomputes the normals in the main pass. This isn't ideal
since it's doing redundant work.

## Solution

- Use the normal texture from the prepass in the main pass

## Notes

~~I used `NORMAL_PREPASS_ENABLED` as a shader_def because
`NORMAL_PREPASS` is currently used to signify that it is running in the
prepass while this shader_def need to indicate the prepass is done and
the normal prepass was ran before. I'm not sure if there's a better way
to name this.~~
This commit is contained in:
IceSentry 2023-03-29 14:04:40 -04:00 committed by GitHub
parent 21dc3abe1b
commit 0859f675c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 18 additions and 0 deletions

View File

@ -7,6 +7,7 @@ use bevy_app::{App, Plugin};
use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle};
use bevy_core_pipeline::{
core_3d::{AlphaMask3d, Opaque3d, Transparent3d},
prepass::NormalPrepass,
tonemapping::{DebandDither, Tonemapping},
};
use bevy_derive::{Deref, DerefMut};
@ -380,6 +381,7 @@ pub fn queue_material_meshes<M: Material>(
Option<&Tonemapping>,
Option<&DebandDither>,
Option<&EnvironmentMapLight>,
Option<&NormalPrepass>,
&mut RenderPhase<Opaque3d>,
&mut RenderPhase<AlphaMask3d>,
&mut RenderPhase<Transparent3d>,
@ -393,6 +395,7 @@ pub fn queue_material_meshes<M: Material>(
tonemapping,
dither,
environment_map,
normal_prepass,
mut opaque_phase,
mut alpha_mask_phase,
mut transparent_phase,
@ -405,6 +408,10 @@ pub fn queue_material_meshes<M: Material>(
let mut view_key = MeshPipelineKey::from_msaa_samples(msaa.samples())
| MeshPipelineKey::from_hdr(view.hdr);
if normal_prepass.is_some() {
view_key |= MeshPipelineKey::NORMAL_PREPASS;
}
let environment_map_loaded = match environment_map {
Some(environment_map) => environment_map.is_loaded(&images),
None => false,

View File

@ -665,6 +665,10 @@ impl SpecializedMeshPipeline for MeshPipeline {
let mut shader_defs = Vec::new();
let mut vertex_attributes = Vec::new();
if key.contains(MeshPipelineKey::NORMAL_PREPASS) {
shader_defs.push("LOAD_PREPASS_NORMALS".into());
}
if layout.contains(Mesh::ATTRIBUTE_POSITION) {
shader_defs.push("VERTEX_POSITIONS".into());
vertex_attributes.push(Mesh::ATTRIBUTE_POSITION.at_shader_location(0));

View File

@ -10,6 +10,8 @@
#import bevy_pbr::fog
#import bevy_pbr::pbr_functions
#import bevy_pbr::prepass_utils
struct FragmentInput {
@builtin(front_facing) is_front: bool,
@builtin(position) frag_coord: vec4<f32>,
@ -69,11 +71,16 @@ fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
#endif
pbr_input.frag_coord = in.frag_coord;
pbr_input.world_position = in.world_position;
#ifdef LOAD_PREPASS_NORMALS
pbr_input.world_normal = prepass_normal(in.frag_coord, 0u);
#else // LOAD_PREPASS_NORMALS
pbr_input.world_normal = prepare_world_normal(
in.world_normal,
(material.flags & STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u,
in.is_front,
);
#endif // LOAD_PREPASS_NORMALS
pbr_input.is_orthographic = view.projection[3].w == 1.0;