Skip to content

Commit 10f5c92

Browse files
authored
improve shader import model (#5703)
# Objective operate on naga IR directly to improve handling of shader modules. - give codespan reporting into imported modules - allow glsl to be used from wgsl and vice-versa the ultimate objective is to make it possible to - provide user hooks for core shader functions (to modify light behaviour within the standard pbr pipeline, for example) - make automatic binding slot allocation possible but ... since this is already big, adds some value and (i think) is at feature parity with the existing code, i wanted to push this now. ## Solution i made a crate called naga_oil (https://github.com/robtfm/naga_oil - unpublished for now, could be part of bevy) which manages modules by - building each module independantly to naga IR - creating "header" files for each supported language, which are used to build dependent modules/shaders - make final shaders by combining the shader IR with the IR for imported modules then integrated this into bevy, replacing some of the existing shader processing stuff. also reworked examples to reflect this. ## Migration Guide shaders that don't use `#import` directives should work without changes. the most notable user-facing difference is that imported functions/variables/etc need to be qualified at point of use, and there's no "leakage" of visible stuff into your shader scope from the imports of your imports, so if you used things imported by your imports, you now need to import them directly and qualify them. the current strategy of including/'spreading' `mesh_vertex_output` directly into a struct doesn't work any more, so these need to be modified as per the examples (e.g. color_material.wgsl, or many others). mesh data is assumed to be in bindgroup 2 by default, if mesh data is bound into bindgroup 1 instead then the shader def `MESH_BINDGROUP_1` needs to be added to the pipeline shader_defs.
1 parent 0f4d16a commit 10f5c92

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+950
-3144
lines changed

assets/shaders/animate_shader.wgsl

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#import bevy_pbr::mesh_types
21
// The time since startup data is in the globals binding which is part of the mesh_view_bindings import
3-
#import bevy_pbr::mesh_view_bindings
2+
#import bevy_pbr::mesh_view_bindings globals
3+
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
44

55
fn oklab_to_linear_srgb(c: vec3<f32>) -> vec3<f32> {
66
let L = c.x;
@@ -22,12 +22,8 @@ fn oklab_to_linear_srgb(c: vec3<f32>) -> vec3<f32> {
2222
);
2323
}
2424

25-
struct FragmentInput {
26-
#import bevy_pbr::mesh_vertex_output
27-
}
28-
2925
@fragment
30-
fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
26+
fn fragment(in: MeshVertexOutput) -> @location(0) vec4<f32> {
3127
let speed = 2.0;
3228
// The globals binding contains various global values like time
3329
// which is the time since startup in seconds

assets/shaders/array_texture.wgsl

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,51 @@
1-
#import bevy_pbr::mesh_view_bindings
2-
#import bevy_pbr::mesh_bindings
3-
4-
#import bevy_pbr::pbr_types
5-
#import bevy_pbr::utils
6-
#import bevy_pbr::clustered_forward
7-
#import bevy_pbr::lighting
8-
#import bevy_pbr::shadows
9-
#import bevy_pbr::fog
10-
#import bevy_pbr::pbr_functions
11-
#import bevy_pbr::pbr_ambient
1+
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
2+
#import bevy_pbr::mesh_view_bindings view
3+
#import bevy_pbr::pbr_types STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT
4+
#import bevy_core_pipeline::tonemapping tone_mapping
5+
#import bevy_pbr::pbr_functions as fns
126

137
@group(1) @binding(0)
148
var my_array_texture: texture_2d_array<f32>;
159
@group(1) @binding(1)
1610
var my_array_texture_sampler: sampler;
1711

18-
struct FragmentInput {
19-
@builtin(front_facing) is_front: bool,
20-
@builtin(position) frag_coord: vec4<f32>,
21-
#import bevy_pbr::mesh_vertex_output
22-
};
23-
2412
@fragment
25-
fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
26-
let layer = i32(in.world_position.x) & 0x3;
13+
fn fragment(
14+
@builtin(front_facing) is_front: bool,
15+
mesh: MeshVertexOutput,
16+
) -> @location(0) vec4<f32> {
17+
let layer = i32(mesh.world_position.x) & 0x3;
2718

2819
// Prepare a 'processed' StandardMaterial by sampling all textures to resolve
2920
// the material members
30-
var pbr_input: PbrInput = pbr_input_new();
21+
var pbr_input: fns::PbrInput = fns::pbr_input_new();
3122

32-
pbr_input.material.base_color = textureSample(my_array_texture, my_array_texture_sampler, in.uv, layer);
23+
pbr_input.material.base_color = textureSample(my_array_texture, my_array_texture_sampler, mesh.uv, layer);
3324
#ifdef VERTEX_COLORS
34-
pbr_input.material.base_color = pbr_input.material.base_color * in.color;
25+
pbr_input.material.base_color = pbr_input.material.base_color * mesh.color;
3526
#endif
3627

37-
pbr_input.frag_coord = in.frag_coord;
38-
pbr_input.world_position = in.world_position;
39-
pbr_input.world_normal = prepare_world_normal(
40-
in.world_normal,
28+
pbr_input.frag_coord = mesh.position;
29+
pbr_input.world_position = mesh.world_position;
30+
pbr_input.world_normal = fns::prepare_world_normal(
31+
mesh.world_normal,
4132
(pbr_input.material.flags & STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u,
42-
in.is_front,
33+
is_front,
4334
);
4435

4536
pbr_input.is_orthographic = view.projection[3].w == 1.0;
4637

47-
pbr_input.N = apply_normal_mapping(
38+
pbr_input.N = fns::apply_normal_mapping(
4839
pbr_input.material.flags,
49-
pbr_input.world_normal,
40+
mesh.world_normal,
5041
#ifdef VERTEX_TANGENTS
5142
#ifdef STANDARDMATERIAL_NORMAL_MAP
52-
in.world_tangent,
43+
mesh.world_tangent,
5344
#endif
5445
#endif
55-
in.uv,
46+
mesh.uv,
5647
);
57-
pbr_input.V = calculate_view(in.world_position, pbr_input.is_orthographic);
48+
pbr_input.V = fns::calculate_view(mesh.world_position, pbr_input.is_orthographic);
5849

59-
return tone_mapping(pbr(pbr_input));
50+
return tone_mapping(fns::pbr(pbr_input), view.color_grading);
6051
}

assets/shaders/cubemap_unlit.wgsl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#import bevy_pbr::mesh_view_bindings
1+
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
22

33
#ifdef CUBEMAP_ARRAY
44
@group(1) @binding(0)
@@ -13,9 +13,9 @@ var base_color_sampler: sampler;
1313

1414
@fragment
1515
fn fragment(
16-
#import bevy_pbr::mesh_vertex_output
16+
mesh: MeshVertexOutput,
1717
) -> @location(0) vec4<f32> {
18-
let fragment_position_view_lh = world_position.xyz * vec3<f32>(1.0, 1.0, -1.0);
18+
let fragment_position_view_lh = mesh.world_position.xyz * vec3<f32>(1.0, 1.0, -1.0);
1919
return textureSample(
2020
base_color_texture,
2121
base_color_sampler,

assets/shaders/custom_gltf_2d.wgsl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
#import bevy_sprite::mesh2d_view_bindings
2-
#import bevy_sprite::mesh2d_bindings
3-
#import bevy_sprite::mesh2d_functions
1+
#import bevy_sprite::mesh2d_view_bindings globals
2+
#import bevy_sprite::mesh2d_bindings mesh
3+
#import bevy_sprite::mesh2d_functions mesh2d_position_local_to_clip
44

55
struct Vertex {
66
@location(0) position: vec3<f32>,

assets/shaders/custom_material.frag

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ layout(set = 1, binding = 0) uniform CustomMaterial {
1010
layout(set = 1, binding = 1) uniform texture2D CustomMaterial_texture;
1111
layout(set = 1, binding = 2) uniform sampler CustomMaterial_sampler;
1212

13+
// wgsl modules can be imported and used in glsl
14+
// FIXME - this doesn't work any more ...
15+
// #import bevy_pbr::pbr_functions as PbrFuncs
1316

1417
void main() {
18+
// o_Target = PbrFuncs::tone_mapping(Color * texture(sampler2D(CustomMaterial_texture,CustomMaterial_sampler), v_Uv));
1519
o_Target = Color * texture(sampler2D(CustomMaterial_texture,CustomMaterial_sampler), v_Uv);
1620
}

assets/shaders/custom_material.wgsl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
2+
13
struct CustomMaterial {
24
color: vec4<f32>,
35
};
@@ -11,7 +13,7 @@ var base_color_sampler: sampler;
1113

1214
@fragment
1315
fn fragment(
14-
#import bevy_pbr::mesh_vertex_output
16+
mesh: MeshVertexOutput,
1517
) -> @location(0) vec4<f32> {
16-
return material.color * textureSample(base_color_texture, base_color_sampler, uv);
18+
return material.color * textureSample(base_color_texture, base_color_sampler, mesh.uv);
1719
}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
#import bevy_pbr::mesh_view_bindings
2-
#import bevy_pbr::utils
1+
#import bevy_pbr::mesh_view_bindings view
2+
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
3+
#import bevy_pbr::utils coords_to_viewport_uv
34

45
@group(1) @binding(0)
56
var texture: texture_2d<f32>;
@@ -8,10 +9,9 @@ var texture_sampler: sampler;
89

910
@fragment
1011
fn fragment(
11-
@builtin(position) position: vec4<f32>,
12-
#import bevy_pbr::mesh_vertex_output
12+
mesh: MeshVertexOutput,
1313
) -> @location(0) vec4<f32> {
14-
let viewport_uv = coords_to_viewport_uv(position.xy, view.viewport);
14+
let viewport_uv = coords_to_viewport_uv(mesh.position.xy, view.viewport);
1515
let color = textureSample(texture, texture_sampler, viewport_uv);
1616
return color;
1717
}

assets/shaders/custom_vertex_attribute.wgsl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
#import bevy_pbr::mesh_view_bindings
2-
#import bevy_pbr::mesh_bindings
1+
#import bevy_pbr::mesh_bindings mesh
2+
#import bevy_pbr::mesh_functions mesh_position_local_to_clip
33

44
struct CustomMaterial {
55
color: vec4<f32>,
66
};
77
@group(1) @binding(0)
88
var<uniform> material: CustomMaterial;
99

10-
// NOTE: Bindings must come before functions that use them!
11-
#import bevy_pbr::mesh_functions
12-
1310
struct Vertex {
1411
@location(0) position: vec3<f32>,
1512
@location(1) blend_color: vec4<f32>,
@@ -23,7 +20,10 @@ struct VertexOutput {
2320
@vertex
2421
fn vertex(vertex: Vertex) -> VertexOutput {
2522
var out: VertexOutput;
26-
out.clip_position = mesh_position_local_to_clip(mesh.model, vec4<f32>(vertex.position, 1.0));
23+
out.clip_position = mesh_position_local_to_clip(
24+
mesh.model,
25+
vec4<f32>(vertex.position, 1.0)
26+
);
2727
out.blend_color = vertex.blend_color;
2828
return out;
2929
}

assets/shaders/instancing.wgsl

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
1-
#import bevy_pbr::mesh_types
2-
#import bevy_pbr::mesh_view_bindings
3-
4-
@group(1) @binding(0)
5-
var<uniform> mesh: Mesh;
6-
7-
// NOTE: Bindings must come before functions that use them!
8-
#import bevy_pbr::mesh_functions
1+
#import bevy_pbr::mesh_functions mesh_position_local_to_clip
2+
#import bevy_pbr::mesh_bindings mesh
93

104
struct Vertex {
115
@location(0) position: vec3<f32>,
@@ -25,7 +19,10 @@ struct VertexOutput {
2519
fn vertex(vertex: Vertex) -> VertexOutput {
2620
let position = vertex.position * vertex.i_pos_scale.w + vertex.i_pos_scale.xyz;
2721
var out: VertexOutput;
28-
out.clip_position = mesh_position_local_to_clip(mesh.model, vec4<f32>(position, 1.0));
22+
out.clip_position = mesh_position_local_to_clip(
23+
mesh.model,
24+
vec4<f32>(position, 1.0)
25+
);
2926
out.color = vertex.i_color;
3027
return out;
3128
}

assets/shaders/line_material.wgsl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
2+
13
struct LineMaterial {
24
color: vec4<f32>,
35
};
@@ -7,7 +9,7 @@ var<uniform> material: LineMaterial;
79

810
@fragment
911
fn fragment(
10-
#import bevy_pbr::mesh_vertex_output
12+
mesh: MeshVertexOutput,
1113
) -> @location(0) vec4<f32> {
1214
return material.color;
1315
}

assets/shaders/post_processing.wgsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
// As you can see, the triangle ends up bigger than the screen.
2121
//
2222
// You don't need to worry about this too much since bevy will compute the correct UVs for you.
23-
#import bevy_core_pipeline::fullscreen_vertex_shader
23+
#import bevy_core_pipeline::fullscreen_vertex_shader FullscreenVertexOutput
2424

2525
@group(0) @binding(0)
2626
var screen_texture: texture_2d<f32>;

assets/shaders/shader_defs.wgsl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
2+
13
struct CustomMaterial {
24
color: vec4<f32>,
35
};
@@ -7,7 +9,7 @@ var<uniform> material: CustomMaterial;
79

810
@fragment
911
fn fragment(
10-
#import bevy_pbr::mesh_vertex_output
12+
mesh: MeshVertexOutput,
1113
) -> @location(0) vec4<f32> {
1214
#ifdef IS_RED
1315
return vec4<f32>(1.0, 0.0, 0.0, 1.0);

assets/shaders/show_prepass.wgsl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#import bevy_pbr::mesh_types
2-
#import bevy_pbr::mesh_view_bindings
2+
#import bevy_pbr::mesh_view_bindings globals
33
#import bevy_pbr::prepass_utils
4+
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
45

56
struct ShowPrepassSettings {
67
show_depth: u32,
@@ -14,23 +15,22 @@ var<uniform> settings: ShowPrepassSettings;
1415

1516
@fragment
1617
fn fragment(
17-
@builtin(position) frag_coord: vec4<f32>,
1818
#ifdef MULTISAMPLED
1919
@builtin(sample_index) sample_index: u32,
2020
#endif
21-
#import bevy_pbr::mesh_vertex_output
21+
mesh: MeshVertexOutput,
2222
) -> @location(0) vec4<f32> {
2323
#ifndef MULTISAMPLED
2424
let sample_index = 0u;
2525
#endif
2626
if settings.show_depth == 1u {
27-
let depth = prepass_depth(frag_coord, sample_index);
27+
let depth = bevy_pbr::prepass_utils::prepass_depth(mesh.position, sample_index);
2828
return vec4(depth, depth, depth, 1.0);
2929
} else if settings.show_normals == 1u {
30-
let normal = prepass_normal(frag_coord, sample_index);
30+
let normal = bevy_pbr::prepass_utils::prepass_normal(mesh.position, sample_index);
3131
return vec4(normal, 1.0);
3232
} else if settings.show_motion_vectors == 1u {
33-
let motion_vector = prepass_motion_vector(frag_coord, sample_index);
33+
let motion_vector = bevy_pbr::prepass_utils::prepass_motion_vector(mesh.position, sample_index);
3434
return vec4(motion_vector / globals.delta_time, 0.0, 1.0);
3535
}
3636

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
2+
13
@group(1) @binding(0)
24
var textures: binding_array<texture_2d<f32>>;
35
@group(1) @binding(1)
@@ -7,11 +9,11 @@ var nearest_sampler: sampler;
79

810
@fragment
911
fn fragment(
10-
#import bevy_pbr::mesh_vertex_output
12+
mesh: MeshVertexOutput,
1113
) -> @location(0) vec4<f32> {
1214
// Select the texture to sample from using non-uniform uv coordinates
13-
let coords = clamp(vec2<u32>(uv * 4.0), vec2<u32>(0u), vec2<u32>(3u));
15+
let coords = clamp(vec2<u32>(mesh.uv * 4.0), vec2<u32>(0u), vec2<u32>(3u));
1416
let index = coords.y * 4u + coords.x;
15-
let inner_uv = fract(uv * 4.0);
17+
let inner_uv = fract(mesh.uv * 4.0);
1618
return textureSample(textures[index], nearest_sampler, inner_uv);
1719
}

assets/shaders/tonemapping_test_patterns.wgsl

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,12 @@
11
#import bevy_pbr::mesh_view_bindings
22
#import bevy_pbr::mesh_bindings
3-
#import bevy_pbr::utils
3+
#import bevy_pbr::mesh_vertex_output MeshVertexOutput
4+
#import bevy_pbr::utils PI
45

56
#ifdef TONEMAP_IN_SHADER
67
#import bevy_core_pipeline::tonemapping
78
#endif
89

9-
struct FragmentInput {
10-
@builtin(front_facing) is_front: bool,
11-
@builtin(position) frag_coord: vec4<f32>,
12-
#import bevy_pbr::mesh_vertex_output
13-
};
14-
1510
// Sweep across hues on y axis with value from 0.0 to +15EV across x axis
1611
// quantized into 24 steps for both axis.
1712
fn color_sweep(uv: vec2<f32>) -> vec3<f32> {
@@ -47,7 +42,9 @@ fn continuous_hue(uv: vec2<f32>) -> vec3<f32> {
4742
}
4843

4944
@fragment
50-
fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
45+
fn fragment(
46+
in: MeshVertexOutput,
47+
) -> @location(0) vec4<f32> {
5148
var uv = in.uv;
5249
var out = vec3(0.0);
5350
if uv.y > 0.5 {
@@ -58,7 +55,7 @@ fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
5855
}
5956
var color = vec4(out, 1.0);
6057
#ifdef TONEMAP_IN_SHADER
61-
color = tone_mapping(color);
58+
color = tone_mapping(color, bevy_pbr::mesh_view_bindings::view.color_grading);
6259
#endif
6360
return color;
6461
}

0 commit comments

Comments
 (0)