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