@@ -20,14 +20,13 @@ use bevy_render::{
20
20
render_resource:: * ,
21
21
renderer:: { RenderDevice , RenderQueue } ,
22
22
texture:: Image ,
23
- view:: { ComputedVisibility , ExtractedView , ViewUniforms } ,
23
+ view:: { ComputedVisibility , ExtractedView , RenderLayers , ViewUniforms } ,
24
24
Extract , RenderApp , RenderStage ,
25
25
} ;
26
26
use bevy_sprite:: { Rect , SpriteAssetEvents , TextureAtlas } ;
27
27
use bevy_text:: { DefaultTextPipeline , Text } ;
28
28
use bevy_transform:: components:: GlobalTransform ;
29
- use bevy_utils:: FloatOrd ;
30
- use bevy_utils:: HashMap ;
29
+ use bevy_utils:: { FloatOrd , HashMap } ;
31
30
use bevy_window:: { WindowId , Windows } ;
32
31
use bytemuck:: { Pod , Zeroable } ;
33
32
use std:: ops:: Range ;
@@ -166,6 +165,7 @@ pub struct ExtractedUiNode {
166
165
pub image : Handle < Image > ,
167
166
pub atlas_size : Option < Vec2 > ,
168
167
pub clip : Option < Rect > ,
168
+ pub render_layers : RenderLayers ,
169
169
}
170
170
171
171
#[ derive( Default ) ]
@@ -183,12 +183,13 @@ pub fn extract_uinodes(
183
183
& UiColor ,
184
184
& UiImage ,
185
185
& ComputedVisibility ,
186
+ & RenderLayers ,
186
187
Option < & CalculatedClip > ,
187
188
) > ,
188
189
> ,
189
190
) {
190
191
extracted_uinodes. uinodes . clear ( ) ;
191
- for ( uinode, transform, color, image, visibility, clip) in uinode_query. iter ( ) {
192
+ for ( uinode, transform, color, image, visibility, render_layers , clip) in uinode_query. iter ( ) {
192
193
if !visibility. is_visible ( ) {
193
194
continue ;
194
195
}
@@ -207,6 +208,7 @@ pub fn extract_uinodes(
207
208
image,
208
209
atlas_size : None ,
209
210
clip : clip. map ( |clip| clip. clip ) ,
211
+ render_layers : * render_layers,
210
212
} ) ;
211
213
}
212
214
}
@@ -222,30 +224,36 @@ const UI_CAMERA_FAR: f32 = 1000.0;
222
224
// TODO: Evaluate if we still need this.
223
225
const UI_CAMERA_TRANSFORM_OFFSET : f32 = -0.1 ;
224
226
225
- #[ derive( Component ) ]
226
- pub struct DefaultCameraView ( pub Entity ) ;
227
+ #[ derive( Component , Debug ) ]
228
+ pub struct UiCamera {
229
+ pub entity : Entity ,
230
+ layers : RenderLayers ,
231
+ }
227
232
228
233
pub fn extract_default_ui_camera_view < T : Component > (
229
234
mut commands : Commands ,
230
235
query : Extract < Query < ( Entity , & Camera , Option < & UiCameraConfig > ) , With < T > > > ,
231
236
) {
232
- for ( entity, camera, camera_ui) in query. iter ( ) {
237
+ for ( camera_entity, camera, opt_ui_config) in query. iter ( ) {
238
+ let ui_config = opt_ui_config. cloned ( ) . unwrap_or_default ( ) ;
233
239
// ignore cameras with disabled ui
234
- if matches ! ( camera_ui , Some ( & UiCameraConfig { show_ui : false , .. } ) ) {
240
+ if !ui_config . show_ui {
235
241
continue ;
236
242
}
237
- if let ( Some ( logical_size) , Some ( physical_size) ) = (
238
- camera. logical_viewport_size ( ) ,
239
- camera. physical_viewport_size ( ) ,
240
- ) {
241
- let mut projection = OrthographicProjection {
242
- far : UI_CAMERA_FAR ,
243
- window_origin : WindowOrigin :: BottomLeft ,
244
- depth_calculation : DepthCalculation :: ZDifference ,
245
- ..Default :: default ( )
246
- } ;
247
- projection. update ( logical_size. x , logical_size. y ) ;
248
- let default_camera_view = commands
243
+ let logical_size = if let Some ( logical_size) = camera. logical_viewport_size ( ) {
244
+ logical_size
245
+ } else {
246
+ continue ;
247
+ } ;
248
+ let mut projection = OrthographicProjection {
249
+ far : UI_CAMERA_FAR ,
250
+ window_origin : WindowOrigin :: BottomLeft ,
251
+ depth_calculation : DepthCalculation :: ZDifference ,
252
+ ..Default :: default ( )
253
+ } ;
254
+ projection. update ( logical_size. x , logical_size. y ) ;
255
+ if let Some ( physical_size) = camera. physical_viewport_size ( ) {
256
+ let ui_camera = commands
249
257
. spawn ( )
250
258
. insert ( ExtractedView {
251
259
projection : projection. get_projection_matrix ( ) ,
@@ -258,8 +266,11 @@ pub fn extract_default_ui_camera_view<T: Component>(
258
266
height : physical_size. y ,
259
267
} )
260
268
. id ( ) ;
261
- commands. get_or_spawn ( entity) . insert_bundle ( (
262
- DefaultCameraView ( default_camera_view) ,
269
+ commands. get_or_spawn ( camera_entity) . insert_bundle ( (
270
+ UiCamera {
271
+ entity : ui_camera,
272
+ layers : ui_config. ui_render_layers ,
273
+ } ,
263
274
RenderPhase :: < TransparentUi > :: default ( ) ,
264
275
) ) ;
265
276
}
@@ -278,12 +289,14 @@ pub fn extract_text_uinodes(
278
289
& GlobalTransform ,
279
290
& Text ,
280
291
& ComputedVisibility ,
292
+ & RenderLayers ,
281
293
Option < & CalculatedClip > ,
282
294
) > ,
283
295
> ,
284
296
) {
285
297
let scale_factor = windows. scale_factor ( WindowId :: primary ( ) ) as f32 ;
286
- for ( entity, uinode, global_transform, text, visibility, clip) in uinode_query. iter ( ) {
298
+
299
+ for ( entity, uinode, transform, text, visibility, render_layers, clip) in uinode_query. iter ( ) {
287
300
if !visibility. is_visible ( ) {
288
301
continue ;
289
302
}
@@ -306,7 +319,7 @@ pub fn extract_text_uinodes(
306
319
let atlas_size = Some ( atlas. size ) ;
307
320
308
321
// NOTE: Should match `bevy_text::text2d::extract_text2d_sprite`
309
- let extracted_transform = global_transform . compute_matrix ( )
322
+ let extracted_transform = transform . compute_matrix ( )
310
323
* Mat4 :: from_scale ( Vec3 :: splat ( scale_factor. recip ( ) ) )
311
324
* Mat4 :: from_translation (
312
325
alignment_offset * scale_factor + text_glyph. position . extend ( 0. ) ,
@@ -319,6 +332,7 @@ pub fn extract_text_uinodes(
319
332
image : texture,
320
333
atlas_size,
321
334
clip : clip. map ( |clip| clip. clip ) ,
335
+ render_layers : * render_layers,
322
336
} ) ;
323
337
}
324
338
}
@@ -356,8 +370,10 @@ const QUAD_VERTEX_POSITIONS: [Vec3; 4] = [
356
370
357
371
const QUAD_INDICES : [ usize ; 6 ] = [ 0 , 2 , 3 , 0 , 1 , 2 ] ;
358
372
373
+ /// UI nodes are batched per image and per layer
359
374
#[ derive( Component ) ]
360
375
pub struct UiBatch {
376
+ pub layers : RenderLayers ,
361
377
pub range : Range < u32 > ,
362
378
pub image : Handle < Image > ,
363
379
pub z : f32 ,
@@ -380,20 +396,26 @@ pub fn prepare_uinodes(
380
396
let mut start = 0 ;
381
397
let mut end = 0 ;
382
398
let mut current_batch_handle = Default :: default ( ) ;
399
+ let mut current_batch_layers = Default :: default ( ) ;
383
400
let mut last_z = 0.0 ;
384
401
for extracted_uinode in & extracted_uinodes. uinodes {
385
- if current_batch_handle != extracted_uinode. image {
402
+ let same_layers = current_batch_layers == extracted_uinode. render_layers ;
403
+ let same_handle = current_batch_handle == extracted_uinode. image ;
404
+ if !same_handle || !same_layers {
386
405
if start != end {
387
406
commands. spawn_bundle ( ( UiBatch {
407
+ layers : current_batch_layers,
388
408
range : start..end,
389
409
image : current_batch_handle,
390
410
z : last_z,
391
411
} , ) ) ;
392
412
start = end;
393
413
}
414
+ current_batch_layers = extracted_uinode. render_layers ;
394
415
current_batch_handle = extracted_uinode. image . clone_weak ( ) ;
395
416
}
396
417
418
+ // TODO: the following code is hard to grasp, a refactor would be welcome :)
397
419
let uinode_rect = extracted_uinode. rect ;
398
420
let rect_size = uinode_rect. size ( ) . extend ( 1.0 ) ;
399
421
@@ -471,14 +493,14 @@ pub fn prepare_uinodes(
471
493
color : extracted_uinode. color . as_linear_rgba_f32 ( ) ,
472
494
} ) ;
473
495
}
474
-
475
496
last_z = extracted_uinode. transform . w_axis [ 2 ] ;
476
497
end += QUAD_INDICES . len ( ) as u32 ;
477
498
}
478
499
479
500
// if start != end, there is one last batch to process
480
501
if start != end {
481
502
commands. spawn_bundle ( ( UiBatch {
503
+ layers : current_batch_layers,
482
504
range : start..end,
483
505
image : current_batch_handle,
484
506
z : last_z,
@@ -505,7 +527,7 @@ pub fn queue_uinodes(
505
527
mut image_bind_groups : ResMut < UiImageBindGroups > ,
506
528
gpu_images : Res < RenderAssets < Image > > ,
507
529
ui_batches : Query < ( Entity , & UiBatch ) > ,
508
- mut views : Query < & mut RenderPhase < TransparentUi > > ,
530
+ mut views : Query < ( & mut RenderPhase < TransparentUi > , & UiCamera ) > ,
509
531
events : Res < SpriteAssetEvents > ,
510
532
) {
511
533
// If an image has changed, the GpuImage has (probably) changed
@@ -529,8 +551,11 @@ pub fn queue_uinodes(
529
551
} ) ) ;
530
552
let draw_ui_function = draw_functions. read ( ) . get_id :: < DrawUi > ( ) . unwrap ( ) ;
531
553
let pipeline = pipelines. specialize ( & mut pipeline_cache, & ui_pipeline, UiPipelineKey { } ) ;
532
- for mut transparent_phase in & mut views {
554
+ for ( mut transparent_phase, cam_data ) in & mut views {
533
555
for ( entity, batch) in & ui_batches {
556
+ if !batch. layers . intersects ( & cam_data. layers ) {
557
+ continue ;
558
+ }
534
559
image_bind_groups
535
560
. values
536
561
. entry ( batch. image . clone_weak ( ) )
0 commit comments