mirror of
https://github.com/bevyengine/bevy
synced 2024-11-24 21:53:07 +00:00
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:
parent
26ecfcff43
commit
979c4094d4
26 changed files with 173 additions and 202 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
52
crates/bevy_pbr/src/render/forward_io.wgsl
Normal file
52
crates/bevy_pbr/src/render/forward_io.wgsl
Normal 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>,
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>,
|
||||
|
|
Loading…
Reference in a new issue