@@ -18,8 +18,41 @@ use bevy::{
18
18
prelude:: * ,
19
19
window:: { PresentMode , WindowPlugin } ,
20
20
} ;
21
+ use bevy_internal:: render:: render_resource:: { Extent3d , TextureDimension , TextureFormat } ;
22
+ use clap:: { Parser , ValueEnum } ;
23
+ use rand:: { seq:: SliceRandom , Rng , RngCore , SeedableRng } ;
24
+ use rand_xoshiro:: Xoshiro256StarStar ;
25
+
26
+ #[ derive( Parser , Resource ) ]
27
+ #[ command( author, version, about, long_about = None ) ]
28
+ struct Args {
29
+ /// How the cube instances should be positioned.
30
+ #[ arg( short, long, value_enum, default_value_t=Layout :: Sphere ) ]
31
+ layout : Layout ,
32
+
33
+ /// Whether to step the camera animation by a fixed amount such that each frame is the same across runs.
34
+ #[ arg( short, long, default_value_t = false ) ]
35
+ benchmark : bool ,
36
+
37
+ /// Whether to vary the material data in each instance.
38
+ #[ arg( short, long, default_value_t = false ) ]
39
+ vary_material_data : bool ,
40
+
41
+ /// The number of different textures from which to randomly select the material base color. 0 means no textures.
42
+ #[ arg( short, long, default_value_t = 0 ) ]
43
+ material_texture_count : usize ,
44
+ }
45
+
46
+ #[ derive( Default , Clone , ValueEnum ) ]
47
+ enum Layout {
48
+ Cube ,
49
+ #[ default]
50
+ Sphere ,
51
+ }
21
52
22
53
fn main ( ) {
54
+ let args = Args :: parse ( ) ;
55
+
23
56
App :: new ( )
24
57
. add_plugins ( (
25
58
DefaultPlugins . set ( WindowPlugin {
@@ -32,28 +65,47 @@ fn main() {
32
65
FrameTimeDiagnosticsPlugin ,
33
66
LogDiagnosticsPlugin :: default ( ) ,
34
67
) )
68
+ . insert_resource ( args)
35
69
. add_systems ( Startup , setup)
36
70
. add_systems ( Update , ( move_camera, print_mesh_count) )
37
71
. run ( ) ;
38
72
}
39
73
40
74
fn setup (
41
75
mut commands : Commands ,
76
+ args : Res < Args > ,
42
77
mut meshes : ResMut < Assets < Mesh > > ,
43
- mut materials : ResMut < Assets < StandardMaterial > > ,
78
+ materials : ResMut < Assets < StandardMaterial > > ,
79
+ images : ResMut < Assets < Image > > ,
44
80
) {
45
81
warn ! ( include_str!( "warning_string.txt" ) ) ;
46
82
83
+ let args = args. into_inner ( ) ;
84
+ let images = images. into_inner ( ) ;
85
+ let materials = materials. into_inner ( ) ;
86
+
47
87
const WIDTH : usize = 200 ;
48
88
const HEIGHT : usize = 200 ;
89
+
49
90
let mesh = meshes. add ( Mesh :: from ( shape:: Cube { size : 1.0 } ) ) ;
50
- let material = materials. add ( StandardMaterial {
51
- base_color : Color :: PINK ,
52
- ..default ( )
53
- } ) ;
54
91
55
- match std:: env:: args ( ) . nth ( 1 ) . as_deref ( ) {
56
- Some ( "sphere" ) => {
92
+ let material_textures = init_textures ( args, images) ;
93
+
94
+ let material = materials. add ( Color :: PINK . into ( ) ) ;
95
+ let mut texture_rng = Xoshiro256StarStar :: seed_from_u64 ( 42 ) ;
96
+ let texture_material = if args. material_texture_count == 1 {
97
+ Some ( materials. add ( StandardMaterial {
98
+ base_color : Color :: WHITE ,
99
+ base_color_texture : get_texture ( args, & mut texture_rng, & material_textures) ,
100
+ ..default ( )
101
+ } ) )
102
+ } else {
103
+ None
104
+ } ;
105
+
106
+ let mut color_rng = Xoshiro256StarStar :: seed_from_u64 ( 42 ) ;
107
+ match args. layout {
108
+ Layout :: Sphere => {
57
109
// NOTE: This pattern is good for testing performance of culling as it provides roughly
58
110
// the same number of visible meshes regardless of the viewing angle.
59
111
const N_POINTS : usize = WIDTH * HEIGHT * 4 ;
@@ -66,7 +118,15 @@ fn setup(
66
118
let unit_sphere_p = spherical_polar_to_cartesian ( spherical_polar_theta_phi) ;
67
119
commands. spawn ( PbrBundle {
68
120
mesh : mesh. clone_weak ( ) ,
69
- material : material. clone_weak ( ) ,
121
+ material : get_material (
122
+ args,
123
+ & material,
124
+ texture_material. as_ref ( ) ,
125
+ materials,
126
+ & mut color_rng,
127
+ & mut texture_rng,
128
+ & material_textures,
129
+ ) ,
70
130
transform : Transform :: from_translation ( ( radius * unit_sphere_p) . as_vec3 ( ) ) ,
71
131
..default ( )
72
132
} ) ;
@@ -87,13 +147,29 @@ fn setup(
87
147
// cube
88
148
commands. spawn ( PbrBundle {
89
149
mesh : mesh. clone_weak ( ) ,
90
- material : material. clone_weak ( ) ,
150
+ material : get_material (
151
+ args,
152
+ & material,
153
+ texture_material. as_ref ( ) ,
154
+ materials,
155
+ & mut color_rng,
156
+ & mut texture_rng,
157
+ & material_textures,
158
+ ) ,
91
159
transform : Transform :: from_xyz ( ( x as f32 ) * 2.5 , ( y as f32 ) * 2.5 , 0.0 ) ,
92
160
..default ( )
93
161
} ) ;
94
162
commands. spawn ( PbrBundle {
95
163
mesh : mesh. clone_weak ( ) ,
96
- material : material. clone_weak ( ) ,
164
+ material : get_material (
165
+ args,
166
+ & material,
167
+ texture_material. as_ref ( ) ,
168
+ materials,
169
+ & mut color_rng,
170
+ & mut texture_rng,
171
+ & material_textures,
172
+ ) ,
97
173
transform : Transform :: from_xyz (
98
174
( x as f32 ) * 2.5 ,
99
175
HEIGHT as f32 * 2.5 ,
@@ -103,13 +179,29 @@ fn setup(
103
179
} ) ;
104
180
commands. spawn ( PbrBundle {
105
181
mesh : mesh. clone_weak ( ) ,
106
- material : material. clone_weak ( ) ,
182
+ material : get_material (
183
+ args,
184
+ & material,
185
+ texture_material. as_ref ( ) ,
186
+ materials,
187
+ & mut color_rng,
188
+ & mut texture_rng,
189
+ & material_textures,
190
+ ) ,
107
191
transform : Transform :: from_xyz ( ( x as f32 ) * 2.5 , 0.0 , ( y as f32 ) * 2.5 ) ,
108
192
..default ( )
109
193
} ) ;
110
194
commands. spawn ( PbrBundle {
111
195
mesh : mesh. clone_weak ( ) ,
112
- material : material. clone_weak ( ) ,
196
+ material : get_material (
197
+ args,
198
+ & material,
199
+ texture_material. as_ref ( ) ,
200
+ materials,
201
+ & mut color_rng,
202
+ & mut texture_rng,
203
+ & material_textures,
204
+ ) ,
113
205
transform : Transform :: from_xyz ( 0.0 , ( x as f32 ) * 2.5 , ( y as f32 ) * 2.5 ) ,
114
206
..default ( )
115
207
} ) ;
@@ -139,6 +231,64 @@ fn setup(
139
231
commands. spawn ( DirectionalLightBundle { ..default ( ) } ) ;
140
232
}
141
233
234
+ fn init_textures ( args : & Args , images : & mut Assets < Image > ) -> Vec < Handle < Image > > {
235
+ let mut color_bytes: Vec < u8 > = vec ! [ 0u8 ; args. material_texture_count * 4 ] ;
236
+ Xoshiro256StarStar :: seed_from_u64 ( 42 ) . fill_bytes ( & mut color_bytes) ;
237
+ color_bytes
238
+ . chunks_mut ( 4 )
239
+ . map ( |p| {
240
+ p[ 3 ] = 255 ;
241
+ images. add ( Image :: new_fill (
242
+ Extent3d {
243
+ width : 1 ,
244
+ height : 1 ,
245
+ depth_or_array_layers : 1 ,
246
+ } ,
247
+ TextureDimension :: D2 ,
248
+ p,
249
+ TextureFormat :: Rgba8UnormSrgb ,
250
+ ) )
251
+ } )
252
+ . collect ( )
253
+ }
254
+
255
+ fn get_texture < R : Rng + ?Sized > (
256
+ args : & Args ,
257
+ texture_rng : & mut R ,
258
+ material_textures : & [ Handle < Image > ] ,
259
+ ) -> Option < Handle < Image > > {
260
+ match args. material_texture_count {
261
+ c if c == 0 => None ,
262
+ c if c == 1 => Some ( material_textures[ 0 ] . clone_weak ( ) ) ,
263
+ _ => Some ( material_textures. choose ( texture_rng) . unwrap ( ) . clone_weak ( ) ) ,
264
+ }
265
+ }
266
+
267
+ fn get_material < R : Rng + ?Sized > (
268
+ args : & Args ,
269
+ material : & Handle < StandardMaterial > ,
270
+ texture_material : Option < & Handle < StandardMaterial > > ,
271
+ materials : & mut Assets < StandardMaterial > ,
272
+ color_rng : & mut R ,
273
+ texture_rng : & mut R ,
274
+ material_textures : & [ Handle < Image > ] ,
275
+ ) -> Handle < StandardMaterial > {
276
+ match ( args. vary_material_data , args. material_texture_count ) {
277
+ ( false , 0 ) => material. clone_weak ( ) ,
278
+ ( false , 1 ) => texture_material. unwrap ( ) . clone_weak ( ) ,
279
+ ( false , _) => materials. add ( StandardMaterial {
280
+ base_color : Color :: WHITE ,
281
+ base_color_texture : get_texture ( args, texture_rng, material_textures) ,
282
+ ..default ( )
283
+ } ) ,
284
+ ( true , _) => materials. add ( StandardMaterial {
285
+ base_color : Color :: rgb_u8 ( color_rng. gen ( ) , color_rng. gen ( ) , color_rng. gen ( ) ) ,
286
+ base_color_texture : get_texture ( args, texture_rng, material_textures) ,
287
+ ..default ( )
288
+ } ) ,
289
+ }
290
+ }
291
+
142
292
// NOTE: This epsilon value is apparently optimal for optimizing for the average
143
293
// nearest-neighbor distance. See:
144
294
// http://extremelearning.com.au/how-to-evenly-distribute-points-on-a-sphere-more-effectively-than-the-canonical-fibonacci-lattice/
@@ -159,9 +309,18 @@ fn spherical_polar_to_cartesian(p: DVec2) -> DVec3 {
159
309
}
160
310
161
311
// System for rotating the camera
162
- fn move_camera ( time : Res < Time > , mut camera_query : Query < & mut Transform , With < Camera > > ) {
312
+ fn move_camera (
313
+ time : Res < Time > ,
314
+ args : Res < Args > ,
315
+ mut camera_query : Query < & mut Transform , With < Camera > > ,
316
+ ) {
163
317
let mut camera_transform = camera_query. single_mut ( ) ;
164
- let delta = time. delta_seconds ( ) * 0.15 ;
318
+ let delta = 0.15
319
+ * if args. benchmark {
320
+ 1.0 / 60.0
321
+ } else {
322
+ time. delta_seconds ( )
323
+ } ;
165
324
camera_transform. rotate_z ( delta) ;
166
325
camera_transform. rotate_x ( delta) ;
167
326
}
0 commit comments