# Objective
- Reduce the number of rebindings to enable batching of draw commands
## Solution
- Use the new `GpuArrayBuffer` for `MeshUniform` data to store all
`MeshUniform` data in arrays within fewer bindings
- Sort opaque/alpha mask prepass, opaque/alpha mask main, and shadow
phases also by the batch per-object data binding dynamic offset to
improve performance on WebGL2.
---
## Changelog
- Changed: Per-object `MeshUniform` data is now managed by
`GpuArrayBuffer` as arrays in buffers that need to be indexed into.
## Migration Guide
Accessing the `model` member of an individual mesh object's shader
`Mesh` struct the old way where each `MeshUniform` was stored at its own
dynamic offset:
```rust
struct Vertex {
@location(0) position: vec3<f32>,
};
fn vertex(vertex: Vertex) -> VertexOutput {
var out: VertexOutput;
out.clip_position = mesh_position_local_to_clip(
mesh.model,
vec4<f32>(vertex.position, 1.0)
);
return out;
}
```
The new way where one needs to index into the array of `Mesh`es for the
batch:
```rust
struct Vertex {
@builtin(instance_index) instance_index: u32,
@location(0) position: vec3<f32>,
};
fn vertex(vertex: Vertex) -> VertexOutput {
var out: VertexOutput;
out.clip_position = mesh_position_local_to_clip(
mesh[vertex.instance_index].model,
vec4<f32>(vertex.position, 1.0)
);
return out;
}
```
Note that using the instance_index is the default way to pass the
per-object index into the shader, but if you wish to do custom rendering
approaches you can pass it in however you like.
---------
Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
Co-authored-by: Elabajaba <Elabajaba@users.noreply.github.com>
38 lines
1.1 KiB
WebGPU Shading Language
38 lines
1.1 KiB
WebGPU Shading Language
#import bevy_pbr::mesh_functions mesh_position_local_to_clip
|
|
#import bevy_pbr::mesh_bindings mesh
|
|
|
|
struct Vertex {
|
|
@location(0) position: vec3<f32>,
|
|
@location(1) normal: vec3<f32>,
|
|
@location(2) uv: vec2<f32>,
|
|
|
|
@location(3) i_pos_scale: vec4<f32>,
|
|
@location(4) i_color: vec4<f32>,
|
|
};
|
|
|
|
struct VertexOutput {
|
|
@builtin(position) clip_position: vec4<f32>,
|
|
@location(0) color: vec4<f32>,
|
|
};
|
|
|
|
@vertex
|
|
fn vertex(vertex: Vertex) -> VertexOutput {
|
|
let position = vertex.position * vertex.i_pos_scale.w + vertex.i_pos_scale.xyz;
|
|
var out: VertexOutput;
|
|
// NOTE: The 0 index into the Mesh array is a hack for this example as the
|
|
// instance_index builtin would map to the wrong index in the Mesh array.
|
|
// This index could be passed in via another uniform instead but it's
|
|
// unnecessary for the example.
|
|
out.clip_position = mesh_position_local_to_clip(
|
|
mesh[0].model,
|
|
vec4<f32>(position, 1.0)
|
|
);
|
|
out.color = vertex.i_color;
|
|
return out;
|
|
}
|
|
|
|
@fragment
|
|
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
|
|
return in.color;
|
|
}
|