Path: blob/main/crates/bevy_pbr/src/render/mesh_bindings.rs
6600 views
//! Bind group layout related definitions for the mesh pipeline.12use bevy_math::Mat4;3use bevy_mesh::morph::MAX_MORPH_WEIGHTS;4use bevy_render::{5render_resource::*,6renderer::{RenderAdapter, RenderDevice},7};89use crate::{binding_arrays_are_usable, render::skin::MAX_JOINTS, LightmapSlab};1011const MORPH_WEIGHT_SIZE: usize = size_of::<f32>();1213/// This is used to allocate buffers.14/// The correctness of the value depends on the GPU/platform.15/// The current value is chosen because it is guaranteed to work everywhere.16/// To allow for bigger values, a check must be made for the limits17/// of the GPU at runtime, which would mean not using consts anymore.18pub const MORPH_BUFFER_SIZE: usize = MAX_MORPH_WEIGHTS * MORPH_WEIGHT_SIZE;1920const JOINT_SIZE: usize = size_of::<Mat4>();21pub(crate) const JOINT_BUFFER_SIZE: usize = MAX_JOINTS * JOINT_SIZE;2223/// Individual layout entries.24mod layout_entry {25use core::num::NonZeroU32;2627use super::{JOINT_BUFFER_SIZE, MORPH_BUFFER_SIZE};28use crate::{render::skin, MeshUniform, LIGHTMAPS_PER_SLAB};29use bevy_render::{30render_resource::{31binding_types::{32sampler, storage_buffer_read_only_sized, texture_2d, texture_3d,33uniform_buffer_sized,34},35BindGroupLayoutEntryBuilder, BufferSize, GpuArrayBuffer, SamplerBindingType,36ShaderStages, TextureSampleType,37},38renderer::RenderDevice,39};4041pub(super) fn model(render_device: &RenderDevice) -> BindGroupLayoutEntryBuilder {42GpuArrayBuffer::<MeshUniform>::binding_layout(render_device)43.visibility(ShaderStages::VERTEX_FRAGMENT)44}45pub(super) fn skinning(render_device: &RenderDevice) -> BindGroupLayoutEntryBuilder {46// If we can use storage buffers, do so. Otherwise, fall back to uniform47// buffers.48let size = BufferSize::new(JOINT_BUFFER_SIZE as u64);49if skin::skins_use_uniform_buffers(render_device) {50uniform_buffer_sized(true, size)51} else {52storage_buffer_read_only_sized(false, size)53}54}55pub(super) fn weights() -> BindGroupLayoutEntryBuilder {56uniform_buffer_sized(true, BufferSize::new(MORPH_BUFFER_SIZE as u64))57}58pub(super) fn targets() -> BindGroupLayoutEntryBuilder {59texture_3d(TextureSampleType::Float { filterable: false })60}61pub(super) fn lightmaps_texture_view() -> BindGroupLayoutEntryBuilder {62texture_2d(TextureSampleType::Float { filterable: true }).visibility(ShaderStages::FRAGMENT)63}64pub(super) fn lightmaps_sampler() -> BindGroupLayoutEntryBuilder {65sampler(SamplerBindingType::Filtering).visibility(ShaderStages::FRAGMENT)66}67pub(super) fn lightmaps_texture_view_array() -> BindGroupLayoutEntryBuilder {68texture_2d(TextureSampleType::Float { filterable: true })69.visibility(ShaderStages::FRAGMENT)70.count(NonZeroU32::new(LIGHTMAPS_PER_SLAB as u32).unwrap())71}72pub(super) fn lightmaps_sampler_array() -> BindGroupLayoutEntryBuilder {73sampler(SamplerBindingType::Filtering)74.visibility(ShaderStages::FRAGMENT)75.count(NonZeroU32::new(LIGHTMAPS_PER_SLAB as u32).unwrap())76}77}7879/// Individual [`BindGroupEntry`]80/// for bind groups.81mod entry {82use crate::render::skin;8384use super::{JOINT_BUFFER_SIZE, MORPH_BUFFER_SIZE};85use bevy_render::{86render_resource::{87BindGroupEntry, BindingResource, Buffer, BufferBinding, BufferSize, Sampler,88TextureView, WgpuSampler, WgpuTextureView,89},90renderer::RenderDevice,91};9293fn entry(binding: u32, size: Option<u64>, buffer: &Buffer) -> BindGroupEntry<'_> {94BindGroupEntry {95binding,96resource: BindingResource::Buffer(BufferBinding {97buffer,98offset: 0,99size: size.map(|size| BufferSize::new(size).unwrap()),100}),101}102}103pub(super) fn model(binding: u32, resource: BindingResource) -> BindGroupEntry {104BindGroupEntry { binding, resource }105}106pub(super) fn skinning<'a>(107render_device: &RenderDevice,108binding: u32,109buffer: &'a Buffer,110) -> BindGroupEntry<'a> {111let size = if skin::skins_use_uniform_buffers(render_device) {112Some(JOINT_BUFFER_SIZE as u64)113} else {114None115};116entry(binding, size, buffer)117}118pub(super) fn weights(binding: u32, buffer: &Buffer) -> BindGroupEntry<'_> {119entry(binding, Some(MORPH_BUFFER_SIZE as u64), buffer)120}121pub(super) fn targets(binding: u32, texture: &TextureView) -> BindGroupEntry<'_> {122BindGroupEntry {123binding,124resource: BindingResource::TextureView(texture),125}126}127pub(super) fn lightmaps_texture_view(128binding: u32,129texture: &TextureView,130) -> BindGroupEntry<'_> {131BindGroupEntry {132binding,133resource: BindingResource::TextureView(texture),134}135}136pub(super) fn lightmaps_sampler(binding: u32, sampler: &Sampler) -> BindGroupEntry<'_> {137BindGroupEntry {138binding,139resource: BindingResource::Sampler(sampler),140}141}142pub(super) fn lightmaps_texture_view_array<'a>(143binding: u32,144textures: &'a [&'a WgpuTextureView],145) -> BindGroupEntry<'a> {146BindGroupEntry {147binding,148resource: BindingResource::TextureViewArray(textures),149}150}151pub(super) fn lightmaps_sampler_array<'a>(152binding: u32,153samplers: &'a [&'a WgpuSampler],154) -> BindGroupEntry<'a> {155BindGroupEntry {156binding,157resource: BindingResource::SamplerArray(samplers),158}159}160}161162/// All possible [`BindGroupLayout`]s in bevy's default mesh shader (`mesh.wgsl`).163#[derive(Clone)]164pub struct MeshLayouts {165/// The mesh model uniform (transform) and nothing else.166pub model_only: BindGroupLayout,167168/// Includes the lightmap texture and uniform.169pub lightmapped: BindGroupLayout,170171/// Also includes the uniform for skinning172pub skinned: BindGroupLayout,173174/// Like [`MeshLayouts::skinned`], but includes slots for the previous175/// frame's joint matrices, so that we can compute motion vectors.176pub skinned_motion: BindGroupLayout,177178/// Also includes the uniform and [`MorphAttributes`] for morph targets.179///180/// [`MorphAttributes`]: bevy_mesh::morph::MorphAttributes181pub morphed: BindGroupLayout,182183/// Like [`MeshLayouts::morphed`], but includes a slot for the previous184/// frame's morph weights, so that we can compute motion vectors.185pub morphed_motion: BindGroupLayout,186187/// Also includes both uniforms for skinning and morph targets, also the188/// morph target [`MorphAttributes`] binding.189///190/// [`MorphAttributes`]: bevy_mesh::morph::MorphAttributes191pub morphed_skinned: BindGroupLayout,192193/// Like [`MeshLayouts::morphed_skinned`], but includes slots for the194/// previous frame's joint matrices and morph weights, so that we can195/// compute motion vectors.196pub morphed_skinned_motion: BindGroupLayout,197}198199impl MeshLayouts {200/// Prepare the layouts used by the default bevy [`Mesh`].201///202/// [`Mesh`]: bevy_mesh::Mesh203pub fn new(render_device: &RenderDevice, render_adapter: &RenderAdapter) -> Self {204MeshLayouts {205model_only: Self::model_only_layout(render_device),206lightmapped: Self::lightmapped_layout(render_device, render_adapter),207skinned: Self::skinned_layout(render_device),208skinned_motion: Self::skinned_motion_layout(render_device),209morphed: Self::morphed_layout(render_device),210morphed_motion: Self::morphed_motion_layout(render_device),211morphed_skinned: Self::morphed_skinned_layout(render_device),212morphed_skinned_motion: Self::morphed_skinned_motion_layout(render_device),213}214}215216// ---------- create individual BindGroupLayouts ----------217218fn model_only_layout(render_device: &RenderDevice) -> BindGroupLayout {219render_device.create_bind_group_layout(220"mesh_layout",221&BindGroupLayoutEntries::single(222ShaderStages::empty(),223layout_entry::model(render_device),224),225)226}227228/// Creates the layout for skinned meshes.229fn skinned_layout(render_device: &RenderDevice) -> BindGroupLayout {230render_device.create_bind_group_layout(231"skinned_mesh_layout",232&BindGroupLayoutEntries::with_indices(233ShaderStages::VERTEX,234(235(0, layout_entry::model(render_device)),236// The current frame's joint matrix buffer.237(1, layout_entry::skinning(render_device)),238),239),240)241}242243/// Creates the layout for skinned meshes with the infrastructure to compute244/// motion vectors.245fn skinned_motion_layout(render_device: &RenderDevice) -> BindGroupLayout {246render_device.create_bind_group_layout(247"skinned_motion_mesh_layout",248&BindGroupLayoutEntries::with_indices(249ShaderStages::VERTEX,250(251(0, layout_entry::model(render_device)),252// The current frame's joint matrix buffer.253(1, layout_entry::skinning(render_device)),254// The previous frame's joint matrix buffer.255(6, layout_entry::skinning(render_device)),256),257),258)259}260261/// Creates the layout for meshes with morph targets.262fn morphed_layout(render_device: &RenderDevice) -> BindGroupLayout {263render_device.create_bind_group_layout(264"morphed_mesh_layout",265&BindGroupLayoutEntries::with_indices(266ShaderStages::VERTEX,267(268(0, layout_entry::model(render_device)),269// The current frame's morph weight buffer.270(2, layout_entry::weights()),271(3, layout_entry::targets()),272),273),274)275}276277/// Creates the layout for meshes with morph targets and the infrastructure278/// to compute motion vectors.279fn morphed_motion_layout(render_device: &RenderDevice) -> BindGroupLayout {280render_device.create_bind_group_layout(281"morphed_mesh_layout",282&BindGroupLayoutEntries::with_indices(283ShaderStages::VERTEX,284(285(0, layout_entry::model(render_device)),286// The current frame's morph weight buffer.287(2, layout_entry::weights()),288(3, layout_entry::targets()),289// The previous frame's morph weight buffer.290(7, layout_entry::weights()),291),292),293)294}295296/// Creates the bind group layout for meshes with both skins and morph297/// targets.298fn morphed_skinned_layout(render_device: &RenderDevice) -> BindGroupLayout {299render_device.create_bind_group_layout(300"morphed_skinned_mesh_layout",301&BindGroupLayoutEntries::with_indices(302ShaderStages::VERTEX,303(304(0, layout_entry::model(render_device)),305// The current frame's joint matrix buffer.306(1, layout_entry::skinning(render_device)),307// The current frame's morph weight buffer.308(2, layout_entry::weights()),309(3, layout_entry::targets()),310),311),312)313}314315/// Creates the bind group layout for meshes with both skins and morph316/// targets, in addition to the infrastructure to compute motion vectors.317fn morphed_skinned_motion_layout(render_device: &RenderDevice) -> BindGroupLayout {318render_device.create_bind_group_layout(319"morphed_skinned_motion_mesh_layout",320&BindGroupLayoutEntries::with_indices(321ShaderStages::VERTEX,322(323(0, layout_entry::model(render_device)),324// The current frame's joint matrix buffer.325(1, layout_entry::skinning(render_device)),326// The current frame's morph weight buffer.327(2, layout_entry::weights()),328(3, layout_entry::targets()),329// The previous frame's joint matrix buffer.330(6, layout_entry::skinning(render_device)),331// The previous frame's morph weight buffer.332(7, layout_entry::weights()),333),334),335)336}337338fn lightmapped_layout(339render_device: &RenderDevice,340render_adapter: &RenderAdapter,341) -> BindGroupLayout {342if binding_arrays_are_usable(render_device, render_adapter) {343render_device.create_bind_group_layout(344"lightmapped_mesh_layout",345&BindGroupLayoutEntries::with_indices(346ShaderStages::VERTEX,347(348(0, layout_entry::model(render_device)),349(4, layout_entry::lightmaps_texture_view_array()),350(5, layout_entry::lightmaps_sampler_array()),351),352),353)354} else {355render_device.create_bind_group_layout(356"lightmapped_mesh_layout",357&BindGroupLayoutEntries::with_indices(358ShaderStages::VERTEX,359(360(0, layout_entry::model(render_device)),361(4, layout_entry::lightmaps_texture_view()),362(5, layout_entry::lightmaps_sampler()),363),364),365)366}367}368369// ---------- BindGroup methods ----------370371pub fn model_only(&self, render_device: &RenderDevice, model: &BindingResource) -> BindGroup {372render_device.create_bind_group(373"model_only_mesh_bind_group",374&self.model_only,375&[entry::model(0, model.clone())],376)377}378379pub fn lightmapped(380&self,381render_device: &RenderDevice,382model: &BindingResource,383lightmap_slab: &LightmapSlab,384bindless_lightmaps: bool,385) -> BindGroup {386if bindless_lightmaps {387let (texture_views, samplers) = lightmap_slab.build_binding_arrays();388render_device.create_bind_group(389"lightmapped_mesh_bind_group",390&self.lightmapped,391&[392entry::model(0, model.clone()),393entry::lightmaps_texture_view_array(4, &texture_views),394entry::lightmaps_sampler_array(5, &samplers),395],396)397} else {398let (texture_view, sampler) = lightmap_slab.bindings_for_first_lightmap();399render_device.create_bind_group(400"lightmapped_mesh_bind_group",401&self.lightmapped,402&[403entry::model(0, model.clone()),404entry::lightmaps_texture_view(4, texture_view),405entry::lightmaps_sampler(5, sampler),406],407)408}409}410411/// Creates the bind group for skinned meshes with no morph targets.412pub fn skinned(413&self,414render_device: &RenderDevice,415model: &BindingResource,416current_skin: &Buffer,417) -> BindGroup {418render_device.create_bind_group(419"skinned_mesh_bind_group",420&self.skinned,421&[422entry::model(0, model.clone()),423entry::skinning(render_device, 1, current_skin),424],425)426}427428/// Creates the bind group for skinned meshes with no morph targets, with429/// the infrastructure to compute motion vectors.430///431/// `current_skin` is the buffer of joint matrices for this frame;432/// `prev_skin` is the buffer for the previous frame. The latter is used for433/// motion vector computation. If there is no such applicable buffer,434/// `current_skin` and `prev_skin` will reference the same buffer.435pub fn skinned_motion(436&self,437render_device: &RenderDevice,438model: &BindingResource,439current_skin: &Buffer,440prev_skin: &Buffer,441) -> BindGroup {442render_device.create_bind_group(443"skinned_motion_mesh_bind_group",444&self.skinned_motion,445&[446entry::model(0, model.clone()),447entry::skinning(render_device, 1, current_skin),448entry::skinning(render_device, 6, prev_skin),449],450)451}452453/// Creates the bind group for meshes with no skins but morph targets.454pub fn morphed(455&self,456render_device: &RenderDevice,457model: &BindingResource,458current_weights: &Buffer,459targets: &TextureView,460) -> BindGroup {461render_device.create_bind_group(462"morphed_mesh_bind_group",463&self.morphed,464&[465entry::model(0, model.clone()),466entry::weights(2, current_weights),467entry::targets(3, targets),468],469)470}471472/// Creates the bind group for meshes with no skins but morph targets, in473/// addition to the infrastructure to compute motion vectors.474///475/// `current_weights` is the buffer of morph weights for this frame;476/// `prev_weights` is the buffer for the previous frame. The latter is used477/// for motion vector computation. If there is no such applicable buffer,478/// `current_weights` and `prev_weights` will reference the same buffer.479pub fn morphed_motion(480&self,481render_device: &RenderDevice,482model: &BindingResource,483current_weights: &Buffer,484targets: &TextureView,485prev_weights: &Buffer,486) -> BindGroup {487render_device.create_bind_group(488"morphed_motion_mesh_bind_group",489&self.morphed_motion,490&[491entry::model(0, model.clone()),492entry::weights(2, current_weights),493entry::targets(3, targets),494entry::weights(7, prev_weights),495],496)497}498499/// Creates the bind group for meshes with skins and morph targets.500pub fn morphed_skinned(501&self,502render_device: &RenderDevice,503model: &BindingResource,504current_skin: &Buffer,505current_weights: &Buffer,506targets: &TextureView,507) -> BindGroup {508render_device.create_bind_group(509"morphed_skinned_mesh_bind_group",510&self.morphed_skinned,511&[512entry::model(0, model.clone()),513entry::skinning(render_device, 1, current_skin),514entry::weights(2, current_weights),515entry::targets(3, targets),516],517)518}519520/// Creates the bind group for meshes with skins and morph targets, in521/// addition to the infrastructure to compute motion vectors.522///523/// See the documentation for [`MeshLayouts::skinned_motion`] and524/// [`MeshLayouts::morphed_motion`] above for more information about the525/// `current_skin`, `prev_skin`, `current_weights`, and `prev_weights`526/// buffers.527pub fn morphed_skinned_motion(528&self,529render_device: &RenderDevice,530model: &BindingResource,531current_skin: &Buffer,532current_weights: &Buffer,533targets: &TextureView,534prev_skin: &Buffer,535prev_weights: &Buffer,536) -> BindGroup {537render_device.create_bind_group(538"morphed_skinned_motion_mesh_bind_group",539&self.morphed_skinned_motion,540&[541entry::model(0, model.clone()),542entry::skinning(render_device, 1, current_skin),543entry::weights(2, current_weights),544entry::targets(3, targets),545entry::skinning(render_device, 6, prev_skin),546entry::weights(7, prev_weights),547],548)549}550}551552553