pbr shader cleanup (#10105)

# Objective

cleanup some pbr shader code. improve shader stage io consistency and
make pbr.wgsl (probably many people's first foray into bevy shader code)
a little more human-readable. also fix a couple of small issues with
deferred rendering.

## Solution

mesh_vertex_output: 
- rename to forward_io (to align with prepass_io)
- rename `MeshVertexOutput` to `VertexOutput` (to align with prepass_io)
- move `Vertex` from mesh.wgsl into here (to align with prepass_io)

prepass_io: 
- remove `FragmentInput`, use `VertexOutput` directly (to align with
forward_io)
- rename `VertexOutput::clip_position` to `position` (to align with
forward_io)

pbr.wgsl:
- restructure so we don't need `#ifdefs` on the actual entrypoint, use
VertexOutput and FragmentOutput in all cases and use #ifdefs to import
the right struct definitions.
- rearrange to make the flow clearer
- move alpha_discard up from `pbr_functions::pbr` to avoid needing to
call it on some branches and not others
- add a bunch of comments

deferred_lighting:
- move ssao into the `!unlit` block to reflect forward behaviour
correctly
- fix compile error with deferred + premultiply_alpha

## Migration Guide

in custom material shaders:
- `pbr_functions::pbr` no longer calls to
`pbr_functions::alpha_discard`. if you were using the `pbr` function in
a custom shader with alpha mask mode you now also need to call
alpha_discard manually
- rename imports of `bevy_pbr::mesh_vertex_output` to
`bevy_pbr::forward_io`
- rename instances of `MeshVertexOutput` to `VertexOutput`

in custom material prepass shaders:
- rename instances of `VertexOutput::clip_position` to
`VertexOutput::position`
This commit is contained in:
robtfm 2023-10-13 20:12:40 +01:00 committed by GitHub
parent 26ecfcff43
commit 979c4094d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 173 additions and 202 deletions

View file

@ -1,6 +1,6 @@
// The time since startup data is in the globals binding which is part of the mesh_view_bindings import
#import bevy_pbr::mesh_view_bindings globals
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
#import bevy_pbr::forward_io VertexOutput
fn oklab_to_linear_srgb(c: vec3<f32>) -> vec3<f32> {
let L = c.x;
@ -23,7 +23,7 @@ fn oklab_to_linear_srgb(c: vec3<f32>) -> vec3<f32> {
}
@fragment
fn fragment(in: MeshVertexOutput) -> @location(0) vec4<f32> {
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
let speed = 2.0;
// The globals binding contains various global values like time
// which is the time since startup in seconds

View file

@ -1,4 +1,4 @@
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
#import bevy_pbr::forward_io VertexOutput
#import bevy_pbr::mesh_view_bindings view
#import bevy_pbr::pbr_types STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT, PbrInput, pbr_input_new
#import bevy_core_pipeline::tonemapping tone_mapping
@ -10,7 +10,7 @@
@fragment
fn fragment(
@builtin(front_facing) is_front: bool,
mesh: MeshVertexOutput,
mesh: VertexOutput,
) -> @location(0) vec4<f32> {
let layer = i32(mesh.world_position.x) & 0x3;

View file

@ -1,4 +1,4 @@
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
#import bevy_pbr::forward_io VertexOutput
#ifdef CUBEMAP_ARRAY
@group(1) @binding(0) var base_color_texture: texture_cube_array<f32>;
@ -10,7 +10,7 @@
@fragment
fn fragment(
mesh: MeshVertexOutput,
mesh: VertexOutput,
) -> @location(0) vec4<f32> {
let fragment_position_view_lh = mesh.world_position.xyz * vec3<f32>(1.0, 1.0, -1.0);
return textureSample(

View file

@ -1,4 +1,4 @@
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
#import bevy_pbr::forward_io VertexOutput
// we can import items from shader modules in the assets folder with a quoted path
#import "shaders/custom_material_import.wgsl" COLOR_MULTIPLIER
@ -12,7 +12,7 @@ struct CustomMaterial {
@fragment
fn fragment(
mesh: MeshVertexOutput,
mesh: VertexOutput,
) -> @location(0) vec4<f32> {
return material.color * textureSample(base_color_texture, base_color_sampler, mesh.uv) * COLOR_MULTIPLIER;
}

View file

@ -1,5 +1,5 @@
#import bevy_pbr::mesh_view_bindings view
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
#import bevy_pbr::forward_io VertexOutput
#import bevy_pbr::utils coords_to_viewport_uv
@group(1) @binding(0) var texture: texture_2d<f32>;
@ -7,7 +7,7 @@
@fragment
fn fragment(
mesh: MeshVertexOutput,
mesh: VertexOutput,
) -> @location(0) vec4<f32> {
let viewport_uv = coords_to_viewport_uv(mesh.position.xy, view.viewport);
let color = textureSample(texture, texture_sampler, viewport_uv);

View file

@ -1,6 +1,6 @@
#import bevy_pbr::mesh_view_bindings
#import bevy_pbr::mesh_bindings
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
#import bevy_pbr::forward_io VertexOutput
@group(1) @binding(0) var test_texture_1d: texture_1d<f32>;
@group(1) @binding(1) var test_texture_1d_sampler: sampler;
@ -21,4 +21,4 @@
@group(1) @binding(11) var test_texture_3d_sampler: sampler;
@fragment
fn fragment(in: MeshVertexOutput) {}
fn fragment(in: VertexOutput) {}

View file

@ -1,4 +1,4 @@
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
#import bevy_pbr::forward_io VertexOutput
struct LineMaterial {
color: vec4<f32>,
@ -8,7 +8,7 @@ struct LineMaterial {
@fragment
fn fragment(
mesh: MeshVertexOutput,
mesh: VertexOutput,
) -> @location(0) vec4<f32> {
return material.color;
}

View file

@ -1,4 +1,4 @@
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
#import bevy_pbr::forward_io VertexOutput
struct CustomMaterial {
color: vec4<f32>,
@ -8,7 +8,7 @@ struct CustomMaterial {
@fragment
fn fragment(
mesh: MeshVertexOutput,
mesh: VertexOutput,
) -> @location(0) vec4<f32> {
#ifdef IS_RED
return vec4<f32>(1.0, 0.0, 0.0, 1.0);

View file

@ -1,7 +1,7 @@
#import bevy_pbr::mesh_types
#import bevy_pbr::mesh_view_bindings globals
#import bevy_pbr::prepass_utils
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
#import bevy_pbr::forward_io VertexOutput
struct ShowPrepassSettings {
show_depth: u32,
@ -17,7 +17,7 @@ fn fragment(
#ifdef MULTISAMPLED
@builtin(sample_index) sample_index: u32,
#endif
mesh: MeshVertexOutput,
mesh: VertexOutput,
) -> @location(0) vec4<f32> {
#ifndef MULTISAMPLED
let sample_index = 0u;

View file

@ -1,4 +1,4 @@
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
#import bevy_pbr::forward_io VertexOutput
@group(1) @binding(0) var textures: binding_array<texture_2d<f32>>;
@group(1) @binding(1) var nearest_sampler: sampler;
@ -7,7 +7,7 @@
@fragment
fn fragment(
mesh: MeshVertexOutput,
mesh: VertexOutput,
) -> @location(0) vec4<f32> {
// Select the texture to sample from using non-uniform uv coordinates
let coords = clamp(vec2<u32>(mesh.uv * 4.0), vec2<u32>(0u), vec2<u32>(3u));

View file

@ -1,6 +1,6 @@
#import bevy_pbr::mesh_view_bindings
#import bevy_pbr::mesh_bindings
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
#import bevy_pbr::forward_io VertexOutput
#import bevy_pbr::utils PI
#ifdef TONEMAP_IN_SHADER
@ -43,7 +43,7 @@ fn continuous_hue(uv: vec2<f32>) -> vec3<f32> {
@fragment
fn fragment(
in: MeshVertexOutput,
in: VertexOutput,
) -> @location(0) vec4<f32> {
var uv = in.uv;
var out = vec3(0.0);

View file

@ -56,14 +56,15 @@ fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
var pbr_input = pbr_input_from_deferred_gbuffer(frag_coord, deferred_data);
var output_color = vec4(0.0);
#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
let ssao = textureLoad(screen_space_ambient_occlusion_texture, vec2<i32>(in.position.xy), 0i).r;
let ssao_multibounce = gtao_multibounce(ssao, pbr_input.material.base_color.rgb);
pbr_input.occlusion = min(pbr_input.occlusion, ssao_multibounce);
#endif // SCREEN_SPACE_AMBIENT_OCCLUSION
// NOTE: Unlit bit not set means == 0 is true, so the true case is if lit
if ((pbr_input.material.flags & STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u) {
#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
let ssao = textureLoad(screen_space_ambient_occlusion_texture, vec2<i32>(in.position.xy), 0i).r;
let ssao_multibounce = gtao_multibounce(ssao, pbr_input.material.base_color.rgb);
pbr_input.occlusion = min(pbr_input.occlusion, ssao_multibounce);
#endif // SCREEN_SPACE_AMBIENT_OCCLUSION
output_color = pbr_functions::pbr(pbr_input);
} else {
output_color = pbr_input.material.base_color;
@ -85,9 +86,6 @@ fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {
output_rgb = powsafe(output_rgb, 2.2);
output_color = vec4(output_rgb, output_color.a);
#endif
#endif
#ifdef PREMULTIPLY_ALPHA
output_color = pbr_functions::premultiply_alpha(material.flags, output_color);
#endif
return output_color;

View file

@ -1,6 +1,6 @@
#import bevy_pbr::prepass_bindings
#import bevy_pbr::mesh_functions
#import bevy_pbr::prepass_io Vertex, VertexOutput, FragmentInput, FragmentOutput
#import bevy_pbr::prepass_io Vertex, VertexOutput, FragmentOutput
#import bevy_pbr::skinning
#import bevy_pbr::morph
#import bevy_pbr::mesh_bindings mesh
@ -50,10 +50,10 @@ fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
var model = bevy_pbr::mesh_functions::get_model_matrix(vertex_no_morph.instance_index);
#endif // SKINNED
out.clip_position = bevy_pbr::mesh_functions::mesh_position_local_to_clip(model, vec4(vertex.position, 1.0));
out.position = bevy_pbr::mesh_functions::mesh_position_local_to_clip(model, vec4(vertex.position, 1.0));
#ifdef DEPTH_CLAMP_ORTHO
out.clip_position_unclamped = out.clip_position;
out.clip_position.z = min(out.clip_position.z, 1.0);
out.clip_position_unclamped = out.position;
out.position.z = min(out.position.z, 1.0);
#endif // DEPTH_CLAMP_ORTHO
#ifdef VERTEX_UVS
@ -111,7 +111,7 @@ fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
#ifdef PREPASS_FRAGMENT
@fragment
fn fragment(in: FragmentInput) -> FragmentOutput {
fn fragment(in: VertexOutput) -> FragmentOutput {
var out: FragmentOutput;
#ifdef NORMAL_PREPASS

View file

@ -32,7 +32,9 @@ struct Vertex {
}
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
// This is `clip position` when the struct is used as a vertex stage output
// and `frag coord` when used as a fragment stage input
@builtin(position) position: vec4<f32>,
#ifdef VERTEX_UVS
@location(0) uv: vec2<f32>,
@ -62,36 +64,6 @@ struct VertexOutput {
#endif
}
struct FragmentInput {
@builtin(position) position: vec4<f32>,
#ifdef VERTEX_UVS
@location(0) uv: vec2<f32>,
#endif // VERTEX_UVS
#ifdef NORMAL_PREPASS_OR_DEFERRED_PREPASS
@location(1) world_normal: vec3<f32>,
#ifdef VERTEX_TANGENTS
@location(2) world_tangent: vec4<f32>,
#endif
#endif // NORMAL_PREPASS_OR_DEFERRED_PREPASS
@location(3) world_position: vec4<f32>,
#ifdef MOTION_VECTOR_PREPASS
@location(4) previous_world_position: vec4<f32>,
#endif // MOTION_VECTOR_PREPASS
#ifdef DEPTH_CLAMP_ORTHO
@location(5) clip_position_unclamped: vec4<f32>,
#endif // DEPTH_CLAMP_ORTHO
#ifdef VERTEX_OUTPUT_INSTANCE_INDEX
@location(6) instance_index: u32,
#endif
#ifdef VERTEX_COLORS
@location(7) color: vec4<f32>,
#endif
};
#ifdef PREPASS_FRAGMENT
struct FragmentOutput {
#ifdef NORMAL_PREPASS

View file

@ -0,0 +1,52 @@
#define_import_path bevy_pbr::forward_io
struct Vertex {
@builtin(instance_index) instance_index: u32,
#ifdef VERTEX_POSITIONS
@location(0) position: vec3<f32>,
#endif
#ifdef VERTEX_NORMALS
@location(1) normal: vec3<f32>,
#endif
#ifdef VERTEX_UVS
@location(2) uv: vec2<f32>,
#endif
// (Alternate UVs are at location 3, but they're currently unused here.)
#ifdef VERTEX_TANGENTS
@location(4) tangent: vec4<f32>,
#endif
#ifdef VERTEX_COLORS
@location(5) color: vec4<f32>,
#endif
#ifdef SKINNED
@location(6) joint_indices: vec4<u32>,
@location(7) joint_weights: vec4<f32>,
#endif
#ifdef MORPH_TARGETS
@builtin(vertex_index) index: u32,
#endif
};
struct VertexOutput {
// This is `clip position` when the struct is used as a vertex stage output
// and `frag coord` when used as a fragment stage input
@builtin(position) position: vec4<f32>,
@location(0) world_position: vec4<f32>,
@location(1) world_normal: vec3<f32>,
#ifdef VERTEX_UVS
@location(2) uv: vec2<f32>,
#endif
#ifdef VERTEX_TANGENTS
@location(3) world_tangent: vec4<f32>,
#endif
#ifdef VERTEX_COLORS
@location(4) color: vec4<f32>,
#endif
#ifdef VERTEX_OUTPUT_INSTANCE_INDEX
@location(5) @interpolate(flat) instance_index: u32,
#endif
}
struct FragmentOutput {
@location(0) color: vec4<f32>,
}

View file

@ -62,7 +62,7 @@ use super::skin::SkinIndices;
#[derive(Default)]
pub struct MeshRenderPlugin;
pub const MESH_VERTEX_OUTPUT: Handle<Shader> = Handle::weak_from_u128(2645551199423808407);
pub const FORWARD_IO_HANDLE: Handle<Shader> = Handle::weak_from_u128(2645551199423808407);
pub const MESH_VIEW_TYPES_HANDLE: Handle<Shader> = Handle::weak_from_u128(8140454348013264787);
pub const MESH_VIEW_BINDINGS_HANDLE: Handle<Shader> = Handle::weak_from_u128(9076678235888822571);
pub const MESH_TYPES_HANDLE: Handle<Shader> = Handle::weak_from_u128(2506024101911992377);
@ -74,12 +74,7 @@ pub const MORPH_HANDLE: Handle<Shader> = Handle::weak_from_u128(9709828135876073
impl Plugin for MeshRenderPlugin {
fn build(&self, app: &mut bevy_app::App) {
load_internal_asset!(
app,
MESH_VERTEX_OUTPUT,
"mesh_vertex_output.wgsl",
Shader::from_wgsl
);
load_internal_asset!(app, FORWARD_IO_HANDLE, "forward_io.wgsl", Shader::from_wgsl);
load_internal_asset!(
app,
MESH_VIEW_TYPES_HANDLE,

View file

@ -2,36 +2,9 @@
#import bevy_pbr::skinning
#import bevy_pbr::morph
#import bevy_pbr::mesh_bindings mesh
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
#import bevy_pbr::forward_io Vertex, VertexOutput
#import bevy_render::instance_index get_instance_index
struct Vertex {
@builtin(instance_index) instance_index: u32,
#ifdef VERTEX_POSITIONS
@location(0) position: vec3<f32>,
#endif
#ifdef VERTEX_NORMALS
@location(1) normal: vec3<f32>,
#endif
#ifdef VERTEX_UVS
@location(2) uv: vec2<f32>,
#endif
// (Alternate UVs are at location 3, but they're currently unused here.)
#ifdef VERTEX_TANGENTS
@location(4) tangent: vec4<f32>,
#endif
#ifdef VERTEX_COLORS
@location(5) color: vec4<f32>,
#endif
#ifdef SKINNED
@location(6) joint_indices: vec4<u32>,
@location(7) joint_weights: vec4<f32>,
#endif
#ifdef MORPH_TARGETS
@builtin(vertex_index) index: u32,
#endif
};
#ifdef MORPH_TARGETS
fn morph_vertex(vertex_in: Vertex) -> Vertex {
var vertex = vertex_in;
@ -54,8 +27,8 @@ fn morph_vertex(vertex_in: Vertex) -> Vertex {
#endif
@vertex
fn vertex(vertex_no_morph: Vertex) -> MeshVertexOutput {
var out: MeshVertexOutput;
fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
var out: VertexOutput;
#ifdef MORPH_TARGETS
var vertex = morph_vertex(vertex_no_morph);
@ -118,7 +91,7 @@ fn vertex(vertex_no_morph: Vertex) -> MeshVertexOutput {
@fragment
fn fragment(
mesh: MeshVertexOutput,
mesh: VertexOutput,
) -> @location(0) vec4<f32> {
#ifdef VERTEX_COLORS
return mesh.color;

View file

@ -1,21 +0,0 @@
#define_import_path bevy_pbr::mesh_vertex_output
struct MeshVertexOutput {
// this is `clip position` when the struct is used as a vertex stage output
// and `frag coord` when used as a fragment stage input
@builtin(position) position: vec4<f32>,
@location(0) world_position: vec4<f32>,
@location(1) world_normal: vec3<f32>,
#ifdef VERTEX_UVS
@location(2) uv: vec2<f32>,
#endif
#ifdef VERTEX_TANGENTS
@location(3) world_tangent: vec4<f32>,
#endif
#ifdef VERTEX_COLORS
@location(4) color: vec4<f32>,
#endif
#ifdef VERTEX_OUTPUT_INSTANCE_INDEX
@location(5) @interpolate(flat) instance_index: u32,
#endif
}

View file

@ -17,12 +17,11 @@
#endif
#ifdef DEFERRED_PREPASS
#import bevy_pbr::pbr_deferred_types as pbr_deferred_types
#import bevy_pbr::pbr_deferred_functions as pbr_deferred_functions
#import bevy_pbr::pbr_prepass_functions as pbr_prepass_functions
#import bevy_pbr::prepass_io as prepass_io
#import bevy_pbr::pbr_deferred_functions deferred_gbuffer_from_pbr_input
#import bevy_pbr::pbr_prepass_functions calculate_motion_vector
#import bevy_pbr::prepass_io VertexOutput, FragmentOutput
#else // DEFERRED_PREPASS
#import bevy_pbr::mesh_vertex_output as mesh_vertex_output
#import bevy_pbr::forward_io VertexOutput, FragmentOutput
#endif // DEFERRED_PREPASS
#ifdef MOTION_VECTOR_PREPASS
@ -30,21 +29,16 @@
var<uniform> previous_view_proj: mat4x4<f32>;
#endif // MOTION_VECTOR_PREPASS
@fragment
#ifdef DEFERRED_PREPASS
fn fragment(
in: prepass_io::FragmentInput,
@builtin(front_facing) is_front: bool,
) -> prepass_io::FragmentOutput {
var out: prepass_io::FragmentOutput;
#else // DEFERRED_PREPASS
fn fragment(
in: mesh_vertex_output::MeshVertexOutput,
@builtin(front_facing) is_front: bool,
) -> @location(0) vec4<f32> {
#endif // DEFERRED_PREPASS
var output_color: vec4<f32> = pbr_bindings::material.base_color;
in: VertexOutput,
@builtin(front_facing) is_front: bool,
) -> FragmentOutput {
var out: FragmentOutput;
// calculate unlit color
// ---------------------
var unlit_color: vec4<f32> = pbr_bindings::material.base_color;
let is_orthographic = view.projection[3].w == 1.0;
let V = pbr_functions::calculate_view(in.world_position, is_orthographic);
@ -72,25 +66,31 @@ fn fragment(
#endif
#ifdef VERTEX_COLORS
output_color = output_color * in.color;
unlit_color = unlit_color * in.color;
#endif
#ifdef VERTEX_UVS
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u) {
output_color = output_color * textureSampleBias(pbr_bindings::base_color_texture, pbr_bindings::base_color_sampler, uv, view.mip_bias);
unlit_color = unlit_color * textureSampleBias(pbr_bindings::base_color_texture, pbr_bindings::base_color_sampler, uv, view.mip_bias);
}
#endif // VERTEX_UVS
#endif
// gather pbr lighting data
// ------------------
var pbr_input: pbr_types::PbrInput;
// NOTE: Unlit bit not set means == 0 is true, so the true case is if lit
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u) {
// Prepare a 'processed' StandardMaterial by sampling all textures to resolve
// the material members
var pbr_input: pbr_types::PbrInput;
pbr_input.material.base_color = output_color;
pbr_input.material.reflectance = pbr_bindings::material.reflectance;
pbr_input.material.flags = pbr_bindings::material.flags;
pbr_input.material.alpha_cutoff = pbr_bindings::material.alpha_cutoff;
pbr_input.frag_coord = in.position;
pbr_input.world_position = in.world_position;
pbr_input.is_orthographic = is_orthographic;
pbr_input.flags = mesh[in.instance_index].flags;
// emmissive
// TODO use .a for exposure compensation in HDR
var emissive: vec4<f32> = pbr_bindings::material.emissive;
#ifdef VERTEX_UVS
@ -100,6 +100,7 @@ fn fragment(
#endif
pbr_input.material.emissive = emissive;
// metallic and perceptual roughness
var metallic: f32 = pbr_bindings::material.metallic;
var perceptual_roughness: f32 = pbr_bindings::material.perceptual_roughness;
#ifdef VERTEX_UVS
@ -113,6 +114,7 @@ fn fragment(
pbr_input.material.metallic = metallic;
pbr_input.material.perceptual_roughness = perceptual_roughness;
// occlusion
// TODO: Split into diffuse/specular occlusion?
var occlusion: vec3<f32> = vec3(1.0);
#ifdef VERTEX_UVS
@ -120,26 +122,21 @@ fn fragment(
occlusion = vec3(textureSampleBias(pbr_bindings::occlusion_texture, pbr_bindings::occlusion_sampler, uv, view.mip_bias).r);
}
#endif
#ifndef DEFERRED_PREPASS
#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
let ssao = textureLoad(screen_space_ambient_occlusion_texture, vec2<i32>(in.position.xy), 0i).r;
let ssao_multibounce = gtao_multibounce(ssao, pbr_input.material.base_color.rgb);
occlusion = min(occlusion, ssao_multibounce);
#endif // SCREEN_SPACE_AMBIENT_OCCLUSION
#endif // DEFERRED_PREPASS
#endif
pbr_input.occlusion = occlusion;
pbr_input.frag_coord = in.position;
pbr_input.world_position = in.world_position;
// world normal
pbr_input.world_normal = pbr_functions::prepare_world_normal(
in.world_normal,
(pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u,
is_front,
);
pbr_input.is_orthographic = is_orthographic;
// N (normal vector)
#ifdef LOAD_PREPASS_NORMALS
pbr_input.N = bevy_pbr::prepass_utils::prepass_normal(in.position, 0u);
#else
@ -158,45 +155,48 @@ fn fragment(
);
#endif
// V (view vector)
pbr_input.V = V;
pbr_input.occlusion = occlusion;
pbr_input.flags = mesh[in.instance_index].flags;
#ifdef DEFERRED_PREPASS
pbr_functions::alpha_discard(pbr_bindings::material, output_color);
out.deferred = pbr_deferred_functions::deferred_gbuffer_from_pbr_input(pbr_input);
out.deferred_lighting_pass_id = pbr_bindings::material.deferred_lighting_pass_id;
#ifdef NORMAL_PREPASS
out.normal = vec4(pbr_input.N * 0.5 + vec3(0.5), 1.0);
#endif // NORMAL_PREPASS
#else // DEFERRED_PREPASS
output_color = pbr_functions::pbr(pbr_input);
#endif // DEFERRED_PREPASS
} else { // if UNLIT_BIT != 0
pbr_functions::alpha_discard(pbr_bindings::material, output_color);
#ifdef DEFERRED_PREPASS
var pbr_input = pbr_types::pbr_input_new();
#ifdef DEFERRED_PREPASS
// in deferred mode, we need to fill some of the pbr input data even for unlit materials
// to pass through the gbuffer to the deferred lighting shader
pbr_input = pbr_types::pbr_input_new();
pbr_input.flags = mesh[in.instance_index].flags;
pbr_input.material.flags = pbr_bindings::material.flags;
pbr_input.material.base_color = output_color;
pbr_input.world_position = in.world_position;
pbr_input.world_normal = in.world_normal;
pbr_input.frag_coord = in.position;
out.deferred = pbr_deferred_functions::deferred_gbuffer_from_pbr_input(pbr_input);
out.deferred_lighting_pass_id = pbr_bindings::material.deferred_lighting_pass_id;
#ifdef NORMAL_PREPASS
out.normal = vec4(in.world_normal * 0.5 + vec3(0.5), 1.0);
#endif
#endif // DEFERRED_PREPASS
}
// apply alpha discard
// -------------------
// note even though this is based on the unlit color, it must be done after all texture samples for uniform control flow
unlit_color = pbr_functions::alpha_discard(pbr_bindings::material, unlit_color);
pbr_input.material.base_color = unlit_color;
// generate output
// ---------------
#ifdef DEFERRED_PREPASS
// write the gbuffer
out.deferred = deferred_gbuffer_from_pbr_input(pbr_input);
out.deferred_lighting_pass_id = pbr_bindings::material.deferred_lighting_pass_id;
#ifdef NORMAL_PREPASS
out.normal = vec4(in.world_normal * 0.5 + vec3(0.5), 1.0);
#endif
#ifdef MOTION_VECTOR_PREPASS
out.motion_vector = pbr_prepass_functions::calculate_motion_vector(in.world_position, in.previous_world_position);
out.motion_vector = calculate_motion_vector(in.world_position, in.previous_world_position);
#endif // MOTION_VECTOR_PREPASS
return out;
#else //DEFERRED_PREPASS
// fog
#else // DEFERRED_PREPASS
// in forward mode, we calculate the lit color immediately, and then apply some post-lighting effects here.
// in deferred mode the lit color and these effects will be calculated in the deferred lighting shader
var output_color = unlit_color;
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u) {
output_color = pbr_functions::pbr(pbr_input);
}
if (fog.mode != FOG_MODE_OFF && (pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_FOG_ENABLED_BIT) != 0u) {
output_color = pbr_functions::apply_fog(fog, output_color, in.world_position.xyz, view.world_position.xyz);
}
@ -217,6 +217,10 @@ fn fragment(
output_color = pbr_functions::premultiply_alpha(pbr_bindings::material.flags, output_color);
#endif
return output_color;
// write the final pixel color
out.color = output_color;
#endif //DEFERRED_PREPASS
return out;
}

View file

@ -152,8 +152,6 @@ fn pbr(
let occlusion = in.occlusion;
output_color = alpha_discard(in.material, output_color);
// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
let NdotV = max(dot(in.N, in.V), 0.0001);

View file

@ -11,7 +11,7 @@
#ifdef PREPASS_FRAGMENT
@fragment
fn fragment(
in: prepass_io::FragmentInput,
in: prepass_io::VertexOutput,
@builtin(front_facing) is_front: bool,
) -> prepass_io::FragmentOutput {
bevy_pbr::pbr_prepass_functions::prepass_alpha_discard(in);
@ -59,7 +59,7 @@ fn fragment(
}
#else
@fragment
fn fragment(in: prepass_io::FragmentInput) {
fn fragment(in: prepass_io::VertexOutput) {
bevy_pbr::pbr_prepass_functions::prepass_alpha_discard(in);
}
#endif // PREPASS_FRAGMENT

View file

@ -1,5 +1,5 @@
#define_import_path bevy_pbr::pbr_prepass_functions
#import bevy_pbr::prepass_io as prepass_io
#import bevy_pbr::prepass_io VertexOutput
#import bevy_pbr::prepass_bindings previous_view_proj
#import bevy_pbr::mesh_view_bindings view
@ -11,7 +11,7 @@
const PREMULTIPLIED_ALPHA_CUTOFF = 0.05;
// We can use a simplified version of alpha_discard() here since we only need to handle the alpha_cutoff
fn prepass_alpha_discard(in: prepass_io::FragmentInput) {
fn prepass_alpha_discard(in: VertexOutput) {
#ifdef MAY_DISCARD
var output_color: vec4<f32> = pbr_bindings::material.base_color;
@ -54,4 +54,4 @@ fn calculate_motion_vector(world_position: vec4<f32>, previous_world_position: v
// down where clip space y goes up, so y needs to be flipped.
return (clip_position - previous_clip_position) * vec2(0.5, -0.5);
}
#endif // MOTION_VECTOR_PREPASS
#endif // MOTION_VECTOR_PREPASS

View file

@ -1,4 +1,4 @@
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
#import bevy_pbr::forward_io VertexOutput
struct WireframeMaterial {
color: vec4<f32>,
};
@ -6,6 +6,6 @@ struct WireframeMaterial {
@group(1) @binding(0)
var<uniform> material: WireframeMaterial;
@fragment
fn fragment(in: MeshVertexOutput) -> @location(0) vec4<f32> {
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
return material.color;
}
}

View file

@ -1,5 +1,5 @@
#import bevy_sprite::mesh2d_types Mesh2d
#import bevy_sprite::mesh2d_vertex_output MeshVertexOutput
#import bevy_sprite::mesh2d_vertex_output VertexOutput
#import bevy_sprite::mesh2d_view_bindings view
#ifdef TONEMAP_IN_SHADER
@ -19,7 +19,7 @@ const COLOR_MATERIAL_FLAGS_TEXTURE_BIT: u32 = 1u;
@fragment
fn fragment(
mesh: MeshVertexOutput,
mesh: VertexOutput,
) -> @location(0) vec4<f32> {
var output_color: vec4<f32> = material.color;
#ifdef VERTEX_COLORS

View file

@ -1,6 +1,6 @@
#import bevy_sprite::mesh2d_functions as mesh_functions
#import bevy_sprite::mesh2d_bindings mesh
#import bevy_sprite::mesh2d_vertex_output MeshVertexOutput
#import bevy_sprite::mesh2d_vertex_output VertexOutput
#import bevy_sprite::mesh2d_view_bindings view
#ifdef TONEMAP_IN_SHADER
@ -27,8 +27,8 @@ struct Vertex {
};
@vertex
fn vertex(vertex: Vertex) -> MeshVertexOutput {
var out: MeshVertexOutput;
fn vertex(vertex: Vertex) -> VertexOutput {
var out: VertexOutput;
#ifdef VERTEX_UVS
out.uv = vertex.uv;
#endif
@ -61,7 +61,7 @@ fn vertex(vertex: Vertex) -> MeshVertexOutput {
@fragment
fn fragment(
in: MeshVertexOutput,
in: VertexOutput,
) -> @location(0) vec4<f32> {
#ifdef VERTEX_COLORS
var color = in.color;

View file

@ -1,6 +1,6 @@
#define_import_path bevy_sprite::mesh2d_vertex_output
struct MeshVertexOutput {
struct VertexOutput {
// this is `clip position` when the struct is used as a vertex stage output
// and `frag coord` when used as a fragment stage input
@builtin(position) position: vec4<f32>,