Files
bevy/assets/shaders/array_texture.wgsl
mgi388 d60a1b8166 Add MeshTag to array_texture example to demonstrate layer selection in shader (#21989)
## Objective

- When looking at the `array_texture` example, it wasn't clear to me how
I could send the "layer" to the GPU, but it turns out that [MeshTag is
one recommended
way](https://discord.com/channels/691052431525675048/866787577687310356/1444495450999754823)
to pass this.
- The example previously extracted a fake "layer" from the world
position, but IIUC this isn't the most realistic way to demonstrate
layer selection.

## Solution

- Update the `array_texture` example by using `MeshTag`.
- Add a system to the example that periodically changes the `MeshTag` on
entities to show that the mesh tag can also change dynamically at
runtime (and show how easy it is).

## Testing and showcase

Before, you can see each cube's texture is fixed.

<img width="1280" height="747" alt="image"
src="https://github.com/user-attachments/assets/1ffde7db-8110-4431-b4e8-3a5a4ba5c5db"
/>

After, you can see each cube's texture changes as time passes.


https://github.com/user-attachments/assets/b1227659-5886-4d2c-a401-84b80423c798

----

I'm hoping for a rendering dev to validate this approach is correct, and
useful. I think it is, but [I'm only just starting to
understand](https://discord.com/channels/691052431525675048/866787577687310356/1444888786478829668)
how to use this stuff and it's [possibly not the only
way](https://discord.com/channels/691052431525675048/866787577687310356/1444888304020488365)
so I don't want to submit this if it's the wrong approach to teach
future me's.
2025-12-09 23:38:23 +00:00

62 lines
2.1 KiB
WebGPU Shading Language

#import bevy_pbr::{
forward_io::VertexOutput,
mesh_functions,
mesh_view_bindings::view,
pbr_types::{STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT, PbrInput, pbr_input_new},
pbr_functions as fns,
pbr_bindings,
}
#import bevy_core_pipeline::tonemapping::tone_mapping
@group(#{MATERIAL_BIND_GROUP}) @binding(0) var my_array_texture: texture_2d_array<f32>;
@group(#{MATERIAL_BIND_GROUP}) @binding(1) var my_array_texture_sampler: sampler;
@fragment
fn fragment(
@builtin(front_facing) is_front: bool,
mesh: VertexOutput,
) -> @location(0) vec4<f32> {
// Determine which layer of the array texture to sample from based on the
// mesh tag which originates from the MeshTag component on the entity.
let layer = mesh_functions::get_tag(mesh.instance_index);
// Prepare a 'processed' StandardMaterial by sampling all textures to resolve
// the material members
var pbr_input: PbrInput = pbr_input_new();
pbr_input.material.base_color = textureSample(my_array_texture, my_array_texture_sampler, mesh.uv, layer);
#ifdef VERTEX_COLORS
pbr_input.material.base_color = pbr_input.material.base_color * mesh.color;
#endif
let double_sided = (pbr_input.material.flags & STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u;
pbr_input.frag_coord = mesh.position;
pbr_input.world_position = mesh.world_position;
pbr_input.world_normal = fns::prepare_world_normal(
mesh.world_normal,
double_sided,
is_front,
);
pbr_input.is_orthographic = view.clip_from_view[3].w == 1.0;
pbr_input.N = normalize(pbr_input.world_normal);
#ifdef VERTEX_TANGENTS
let Nt = textureSampleBias(pbr_bindings::normal_map_texture, pbr_bindings::normal_map_sampler, mesh.uv, view.mip_bias).rgb;
let TBN = fns::calculate_tbn_mikktspace(mesh.world_normal, mesh.world_tangent);
pbr_input.N = fns::apply_normal_mapping(
pbr_input.material.flags,
TBN,
double_sided,
is_front,
Nt,
);
#endif
pbr_input.V = fns::calculate_view(mesh.world_position, pbr_input.is_orthographic);
return tone_mapping(fns::apply_pbr_lighting(pbr_input), view.color_grading);
}