@@ -293,11 +293,29 @@ impl ClusterConfig {
293
293
total, z_slices, ..
294
294
} => {
295
295
let aspect_ratio = screen_size. x as f32 / screen_size. y as f32 ;
296
- let per_layer = * total as f32 / * z_slices as f32 ;
296
+ let mut z_slices = * z_slices;
297
+ if * total < z_slices {
298
+ warn ! ( "ClusterConfig has more z-slices than total clusters!" ) ;
299
+ z_slices = * total;
300
+ }
301
+ let per_layer = * total as f32 / z_slices as f32 ;
302
+
297
303
let y = f32:: sqrt ( per_layer / aspect_ratio) ;
298
- let x = ( y * aspect_ratio) . floor ( ) as u32 ;
299
- let y = y. floor ( ) as u32 ;
300
- UVec3 :: new ( x, y, * z_slices)
304
+
305
+ let mut x = ( y * aspect_ratio) as u32 ;
306
+ let mut y = y as u32 ;
307
+
308
+ // check extremes
309
+ if x == 0 {
310
+ x = 1 ;
311
+ y = per_layer as u32 ;
312
+ }
313
+ if y == 0 {
314
+ x = per_layer as u32 ;
315
+ y = 1 ;
316
+ }
317
+
318
+ UVec3 :: new ( x, y, z_slices)
301
319
}
302
320
}
303
321
}
@@ -369,8 +387,12 @@ impl Clusters {
369
387
near : f32 ,
370
388
far : f32 ,
371
389
) -> Self {
390
+ debug_assert ! ( screen_size. x > 0 && screen_size. y > 0 ) ;
391
+ debug_assert ! ( dimensions. x > 0 && dimensions. y > 0 && dimensions. z > 0 ) ;
372
392
Clusters :: new (
373
- ( screen_size + UVec2 :: ONE ) / dimensions. xy ( ) ,
393
+ ( screen_size. as_vec2 ( ) / dimensions. xy ( ) . as_vec2 ( ) )
394
+ . ceil ( )
395
+ . as_uvec2 ( ) ,
374
396
screen_size,
375
397
dimensions. z ,
376
398
near,
@@ -380,13 +402,12 @@ impl Clusters {
380
402
381
403
fn update ( & mut self , tile_size : UVec2 , screen_size : UVec2 , z_slices : u32 ) {
382
404
self . tile_size = tile_size;
383
- self . axis_slices = UVec3 :: new (
384
- ( screen_size. x + 1 ) / tile_size. x ,
385
- ( screen_size. y + 1 ) / tile_size. y ,
386
- z_slices,
387
- ) ;
405
+ self . axis_slices = ( screen_size. as_vec2 ( ) / tile_size. as_vec2 ( ) )
406
+ . ceil ( )
407
+ . as_uvec2 ( )
408
+ . extend ( z_slices) ;
388
409
// NOTE: Maximum 4096 clusters due to uniform buffer size constraints
389
- assert ! ( self . axis_slices. x * self . axis_slices. y * self . axis_slices. z <= 4096 ) ;
410
+ debug_assert ! ( self . axis_slices. x * self . axis_slices. y * self . axis_slices. z <= 4096 ) ;
390
411
}
391
412
}
392
413
@@ -1240,3 +1261,67 @@ pub fn check_light_mesh_visibility(
1240
1261
}
1241
1262
}
1242
1263
}
1264
+
1265
+ #[ cfg( test) ]
1266
+ mod test {
1267
+ use super :: * ;
1268
+
1269
+ fn test_cluster_tiling ( config : ClusterConfig , screen_size : UVec2 ) -> Clusters {
1270
+ let dims = config. dimensions_for_screen_size ( screen_size) ;
1271
+
1272
+ // note: near & far do not affect tiling
1273
+ let clusters = Clusters :: from_screen_size_and_dimensions ( screen_size, dims, 5.0 , 1000.0 ) ;
1274
+
1275
+ // check we cover the screen
1276
+ assert ! ( clusters. tile_size. x * clusters. axis_slices. x >= screen_size. x) ;
1277
+ assert ! ( clusters. tile_size. y * clusters. axis_slices. y >= screen_size. y) ;
1278
+ // check a smaller number of clusters would not cover the screen
1279
+ assert ! ( clusters. tile_size. x * ( clusters. axis_slices. x - 1 ) < screen_size. x) ;
1280
+ assert ! ( clusters. tile_size. y * ( clusters. axis_slices. y - 1 ) < screen_size. y) ;
1281
+ // check a smaller tilesize would not cover the screen
1282
+ assert ! ( ( clusters. tile_size. x - 1 ) * clusters. axis_slices. x < screen_size. x) ;
1283
+ assert ! ( ( clusters. tile_size. y - 1 ) * clusters. axis_slices. y < screen_size. y) ;
1284
+ // check we don't have more clusters than pixels
1285
+ assert ! ( clusters. axis_slices. x <= screen_size. x) ;
1286
+ assert ! ( clusters. axis_slices. y <= screen_size. y) ;
1287
+
1288
+ clusters
1289
+ }
1290
+
1291
+ #[ test]
1292
+ // check tiling for small screen sizes
1293
+ fn test_default_cluster_setup_small_screensizes ( ) {
1294
+ for x in 1 ..100 {
1295
+ for y in 1 ..100 {
1296
+ let screen_size = UVec2 :: new ( x, y) ;
1297
+ let clusters = test_cluster_tiling ( ClusterConfig :: default ( ) , screen_size) ;
1298
+ assert ! (
1299
+ clusters. axis_slices. x * clusters. axis_slices. y * clusters. axis_slices. z
1300
+ <= 4096
1301
+ ) ;
1302
+ }
1303
+ }
1304
+ }
1305
+
1306
+ #[ test]
1307
+ // check tiling for long thin screen sizes
1308
+ fn test_default_cluster_setup_small_x ( ) {
1309
+ for x in 1 ..10 {
1310
+ for y in 1 ..5000 {
1311
+ let screen_size = UVec2 :: new ( x, y) ;
1312
+ let clusters = test_cluster_tiling ( ClusterConfig :: default ( ) , screen_size) ;
1313
+ assert ! (
1314
+ clusters. axis_slices. x * clusters. axis_slices. y * clusters. axis_slices. z
1315
+ <= 4096
1316
+ ) ;
1317
+
1318
+ let screen_size = UVec2 :: new ( y, x) ;
1319
+ let clusters = test_cluster_tiling ( ClusterConfig :: default ( ) , screen_size) ;
1320
+ assert ! (
1321
+ clusters. axis_slices. x * clusters. axis_slices. y * clusters. axis_slices. z
1322
+ <= 4096
1323
+ ) ;
1324
+ }
1325
+ }
1326
+ }
1327
+ }
0 commit comments