bevy/crates/bevy_pbr/src/render/mesh_bindings.rs
Nicola Papale 66f72dd25b
Use wildcard imports in bevy_pbr (#9847)
# Objective

- the style of import used by bevy guarantees merge conflicts when any
file change
- This is especially true when import lists are large, such as in
`bevy_pbr`
- Merge conflicts are tricky to resolve. This bogs down rendering PRs
and makes contributing to bevy's rendering system more difficult than it
needs to

## Solution

- Use wildcard imports to replace multiline import list in `bevy_pbr`

I suspect this is controversial, but I'd like to hear alternatives.
Because this is one of many papercuts that makes developing render
features near impossible.
2023-10-25 08:40:55 +00:00

229 lines
7.8 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::{
BindGroupLayoutEntry, BindingType, BufferBindingType, BufferSize, GpuArrayBuffer,
ShaderStages, TextureSampleType, TextureViewDimension,
},
renderer::RenderDevice,
};
fn buffer(binding: u32, size: u64, visibility: ShaderStages) -> BindGroupLayoutEntry {
BindGroupLayoutEntry {
binding,
visibility,
count: None,
ty: BindingType::Buffer {
ty: BufferBindingType::Uniform,
has_dynamic_offset: true,
min_binding_size: BufferSize::new(size),
},
}
}
pub(super) fn model(render_device: &RenderDevice, binding: u32) -> BindGroupLayoutEntry {
GpuArrayBuffer::<MeshUniform>::binding_layout(
binding,
ShaderStages::VERTEX_FRAGMENT,
render_device,
)
}
pub(super) fn skinning(binding: u32) -> BindGroupLayoutEntry {
buffer(binding, JOINT_BUFFER_SIZE as u64, ShaderStages::VERTEX)
}
pub(super) fn weights(binding: u32) -> BindGroupLayoutEntry {
buffer(binding, MORPH_BUFFER_SIZE as u64, ShaderStages::VERTEX)
}
pub(super) fn targets(binding: u32) -> BindGroupLayoutEntry {
BindGroupLayoutEntry {
binding,
visibility: ShaderStages::VERTEX,
ty: BindingType::Texture {
view_dimension: TextureViewDimension::D3,
sample_type: TextureSampleType::Float { filterable: false },
multisampled: false,
},
count: None,
}
}
}
/// 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(&BindGroupLayoutDescriptor {
entries: &[layout_entry::model(render_device, 0)],
label: Some("mesh_layout"),
})
}
fn skinned_layout(render_device: &RenderDevice) -> BindGroupLayout {
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[
layout_entry::model(render_device, 0),
layout_entry::skinning(1),
],
label: Some("skinned_mesh_layout"),
})
}
fn morphed_layout(render_device: &RenderDevice) -> BindGroupLayout {
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[
layout_entry::model(render_device, 0),
layout_entry::weights(2),
layout_entry::targets(3),
],
label: Some("morphed_mesh_layout"),
})
}
fn morphed_skinned_layout(render_device: &RenderDevice) -> BindGroupLayout {
render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[
layout_entry::model(render_device, 0),
layout_entry::skinning(1),
layout_entry::weights(2),
layout_entry::targets(3),
],
label: Some("morphed_skinned_mesh_layout"),
})
}
// ---------- 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),
],
)
}
}