mirror of
https://github.com/bevyengine/bevy
synced 2024-12-21 02:23:08 +00:00
6d0c11a28f
# Objective
- Follow up to #9694
## Solution
- Same api as #9694 but adapted for `BindGroupLayoutEntry`
- Use the same `ShaderStages` visibilty for all entries by default
- Add `BindingType` helper function that mirror the wgsl equivalent and
that make writing layouts much simpler.
Before:
```rust
let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
label: Some("post_process_bind_group_layout"),
entries: &[
BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Texture {
sample_type: TextureSampleType::Float { filterable: true },
view_dimension: TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
BindGroupLayoutEntry {
binding: 1,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Sampler(SamplerBindingType::Filtering),
count: None,
},
BindGroupLayoutEntry {
binding: 2,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Buffer {
ty: bevy::render::render_resource::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: Some(PostProcessSettings::min_size()),
},
count: None,
},
],
});
```
After:
```rust
let layout = render_device.create_bind_group_layout(
"post_process_bind_group_layout"),
&BindGroupLayoutEntries::sequential(
ShaderStages::FRAGMENT,
(
texture_2d_f32(),
sampler(SamplerBindingType::Filtering),
uniform_buffer(false, Some(PostProcessSettings::min_size())),
),
),
);
```
Here's a more extreme example in bevy_solari:
86dab7f5da
---
## Changelog
- Added `BindGroupLayoutEntries` and all `BindingType` helper functions.
## Migration Guide
`RenderDevice::create_bind_group_layout()` doesn't take a
`BindGroupLayoutDescriptor` anymore. You need to provide the parameters
separately
```rust
// 0.12
let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
label: Some("post_process_bind_group_layout"),
entries: &[
BindGroupLayoutEntry {
// ...
},
],
});
// 0.13
let layout = render_device.create_bind_group_layout(
"post_process_bind_group_layout",
&[
BindGroupLayoutEntry {
// ...
},
],
);
```
## TODO
- [x] implement a `Dynamic` variant
- [x] update the `RenderDevice::create_bind_group_layout()` api to match
the one from `RenderDevice::creat_bind_group()`
- [x] docs
219 lines
7.3 KiB
Rust
219 lines
7.3 KiB
Rust
//! Bind group layout related definitions for the mesh pipeline.
|
|
|
|
use bevy_math::Mat4;
|
|
use bevy_render::{mesh::morph::MAX_MORPH_WEIGHTS, render_resource::*, renderer::RenderDevice};
|
|
|
|
use crate::render::skin::MAX_JOINTS;
|
|
|
|
const MORPH_WEIGHT_SIZE: usize = std::mem::size_of::<f32>();
|
|
pub const MORPH_BUFFER_SIZE: usize = MAX_MORPH_WEIGHTS * MORPH_WEIGHT_SIZE;
|
|
|
|
const JOINT_SIZE: usize = std::mem::size_of::<Mat4>();
|
|
pub(crate) const JOINT_BUFFER_SIZE: usize = MAX_JOINTS * JOINT_SIZE;
|
|
|
|
/// Individual layout entries.
|
|
mod layout_entry {
|
|
use super::{JOINT_BUFFER_SIZE, MORPH_BUFFER_SIZE};
|
|
use crate::MeshUniform;
|
|
use bevy_render::{
|
|
render_resource::{
|
|
binding_types::{texture_3d, uniform_buffer_sized},
|
|
BindGroupLayoutEntryBuilder, BufferSize, GpuArrayBuffer, ShaderStages,
|
|
TextureSampleType,
|
|
},
|
|
renderer::RenderDevice,
|
|
};
|
|
|
|
pub(super) fn model(render_device: &RenderDevice) -> BindGroupLayoutEntryBuilder {
|
|
GpuArrayBuffer::<MeshUniform>::binding_layout(render_device)
|
|
.visibility(ShaderStages::VERTEX_FRAGMENT)
|
|
}
|
|
pub(super) fn skinning() -> BindGroupLayoutEntryBuilder {
|
|
uniform_buffer_sized(true, BufferSize::new(JOINT_BUFFER_SIZE as u64))
|
|
}
|
|
pub(super) fn weights() -> BindGroupLayoutEntryBuilder {
|
|
uniform_buffer_sized(true, BufferSize::new(MORPH_BUFFER_SIZE as u64))
|
|
}
|
|
pub(super) fn targets() -> BindGroupLayoutEntryBuilder {
|
|
texture_3d(TextureSampleType::Float { filterable: false })
|
|
}
|
|
}
|
|
|
|
/// Individual [`BindGroupEntry`]
|
|
/// for bind groups.
|
|
mod entry {
|
|
use super::{JOINT_BUFFER_SIZE, MORPH_BUFFER_SIZE};
|
|
use bevy_render::render_resource::{
|
|
BindGroupEntry, BindingResource, Buffer, BufferBinding, BufferSize, TextureView,
|
|
};
|
|
|
|
fn entry(binding: u32, size: u64, buffer: &Buffer) -> BindGroupEntry {
|
|
BindGroupEntry {
|
|
binding,
|
|
resource: BindingResource::Buffer(BufferBinding {
|
|
buffer,
|
|
offset: 0,
|
|
size: Some(BufferSize::new(size).unwrap()),
|
|
}),
|
|
}
|
|
}
|
|
pub(super) fn model(binding: u32, resource: BindingResource) -> BindGroupEntry {
|
|
BindGroupEntry { binding, resource }
|
|
}
|
|
pub(super) fn skinning(binding: u32, buffer: &Buffer) -> BindGroupEntry {
|
|
entry(binding, JOINT_BUFFER_SIZE as u64, buffer)
|
|
}
|
|
pub(super) fn weights(binding: u32, buffer: &Buffer) -> BindGroupEntry {
|
|
entry(binding, MORPH_BUFFER_SIZE as u64, buffer)
|
|
}
|
|
pub(super) fn targets(binding: u32, texture: &TextureView) -> BindGroupEntry {
|
|
BindGroupEntry {
|
|
binding,
|
|
resource: BindingResource::TextureView(texture),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// All possible [`BindGroupLayout`]s in bevy's default mesh shader (`mesh.wgsl`).
|
|
#[derive(Clone)]
|
|
pub struct MeshLayouts {
|
|
/// The mesh model uniform (transform) and nothing else.
|
|
pub model_only: BindGroupLayout,
|
|
|
|
/// Also includes the uniform for skinning
|
|
pub skinned: BindGroupLayout,
|
|
|
|
/// Also includes the uniform and [`MorphAttributes`] for morph targets.
|
|
///
|
|
/// [`MorphAttributes`]: bevy_render::mesh::morph::MorphAttributes
|
|
pub morphed: BindGroupLayout,
|
|
|
|
/// Also includes both uniforms for skinning and morph targets, also the
|
|
/// morph target [`MorphAttributes`] binding.
|
|
///
|
|
/// [`MorphAttributes`]: bevy_render::mesh::morph::MorphAttributes
|
|
pub morphed_skinned: BindGroupLayout,
|
|
}
|
|
|
|
impl MeshLayouts {
|
|
/// Prepare the layouts used by the default bevy [`Mesh`].
|
|
///
|
|
/// [`Mesh`]: bevy_render::prelude::Mesh
|
|
pub fn new(render_device: &RenderDevice) -> Self {
|
|
MeshLayouts {
|
|
model_only: Self::model_only_layout(render_device),
|
|
skinned: Self::skinned_layout(render_device),
|
|
morphed: Self::morphed_layout(render_device),
|
|
morphed_skinned: Self::morphed_skinned_layout(render_device),
|
|
}
|
|
}
|
|
|
|
// ---------- create individual BindGroupLayouts ----------
|
|
|
|
fn model_only_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
|
render_device.create_bind_group_layout(
|
|
"mesh_layout",
|
|
&BindGroupLayoutEntries::single(
|
|
ShaderStages::empty(),
|
|
layout_entry::model(render_device),
|
|
),
|
|
)
|
|
}
|
|
fn skinned_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
|
render_device.create_bind_group_layout(
|
|
"skinned_mesh_layout",
|
|
&BindGroupLayoutEntries::with_indices(
|
|
ShaderStages::VERTEX,
|
|
(
|
|
(0, layout_entry::model(render_device)),
|
|
(1, layout_entry::skinning()),
|
|
),
|
|
),
|
|
)
|
|
}
|
|
fn morphed_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
|
render_device.create_bind_group_layout(
|
|
"morphed_mesh_layout",
|
|
&BindGroupLayoutEntries::with_indices(
|
|
ShaderStages::VERTEX,
|
|
(
|
|
(0, layout_entry::model(render_device)),
|
|
(2, layout_entry::weights()),
|
|
(3, layout_entry::targets()),
|
|
),
|
|
),
|
|
)
|
|
}
|
|
fn morphed_skinned_layout(render_device: &RenderDevice) -> BindGroupLayout {
|
|
render_device.create_bind_group_layout(
|
|
"morphed_skinned_mesh_layout",
|
|
&BindGroupLayoutEntries::with_indices(
|
|
ShaderStages::VERTEX,
|
|
(
|
|
(0, layout_entry::model(render_device)),
|
|
(1, layout_entry::skinning()),
|
|
(2, layout_entry::weights()),
|
|
(3, layout_entry::targets()),
|
|
),
|
|
),
|
|
)
|
|
}
|
|
|
|
// ---------- BindGroup methods ----------
|
|
|
|
pub fn model_only(&self, render_device: &RenderDevice, model: &BindingResource) -> BindGroup {
|
|
render_device.create_bind_group(
|
|
"model_only_mesh_bind_group",
|
|
&self.model_only,
|
|
&[entry::model(0, model.clone())],
|
|
)
|
|
}
|
|
pub fn skinned(
|
|
&self,
|
|
render_device: &RenderDevice,
|
|
model: &BindingResource,
|
|
skin: &Buffer,
|
|
) -> BindGroup {
|
|
render_device.create_bind_group(
|
|
"skinned_mesh_bind_group",
|
|
&self.skinned,
|
|
&[entry::model(0, model.clone()), entry::skinning(1, skin)],
|
|
)
|
|
}
|
|
pub fn morphed(
|
|
&self,
|
|
render_device: &RenderDevice,
|
|
model: &BindingResource,
|
|
weights: &Buffer,
|
|
targets: &TextureView,
|
|
) -> BindGroup {
|
|
render_device.create_bind_group(
|
|
"morphed_mesh_bind_group",
|
|
&self.morphed,
|
|
&[
|
|
entry::model(0, model.clone()),
|
|
entry::weights(2, weights),
|
|
entry::targets(3, targets),
|
|
],
|
|
)
|
|
}
|
|
pub fn morphed_skinned(
|
|
&self,
|
|
render_device: &RenderDevice,
|
|
model: &BindingResource,
|
|
skin: &Buffer,
|
|
weights: &Buffer,
|
|
targets: &TextureView,
|
|
) -> BindGroup {
|
|
render_device.create_bind_group(
|
|
"morphed_skinned_mesh_bind_group",
|
|
&self.morphed_skinned,
|
|
&[
|
|
entry::model(0, model.clone()),
|
|
entry::skinning(1, skin),
|
|
entry::weights(2, weights),
|
|
entry::targets(3, targets),
|
|
],
|
|
)
|
|
}
|
|
}
|