mirror of
https://github.com/bevyengine/bevy
synced 2025-01-09 19:58:58 +00:00
66f72dd25b
# 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.
229 lines
7.8 KiB
Rust
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),
|
|
],
|
|
)
|
|
}
|
|
}
|