@@ -17,6 +17,10 @@ freecs::ecs! {
1717 ShadowsDemoResources {
1818 time: f32 ,
1919 light_entity: Option <Entity >,
20+ light_cone_entity: Option <Entity >,
21+ spot_light_entity: Option <Entity >,
22+ flashlight_entity: Option <Entity >,
23+ flashlight_enabled: bool ,
2024 spheres: Vec <( Entity , f32 , f32 ) >,
2125 }
2226}
@@ -27,6 +31,10 @@ impl State for ShadowsDemo {
2731
2832 self . resources . time = 0.0 ;
2933 self . resources . light_entity = None ;
34+ self . resources . light_cone_entity = None ;
35+ self . resources . spot_light_entity = None ;
36+ self . resources . flashlight_entity = None ;
37+ self . resources . flashlight_enabled = true ;
3038 self . resources . spheres = Vec :: new ( ) ;
3139
3240 let floor = world. spawn_entities (
@@ -46,6 +54,8 @@ impl State for ShadowsDemo {
4654 scale : Vec3 :: new ( 30.0 , 0.1 , 20.0 ) ,
4755 } ,
4856 ) ;
57+ world. set_global_transform ( floor, GlobalTransform ( nalgebra_glm:: Mat4 :: identity ( ) ) ) ;
58+ world. set_local_transform_dirty ( floor, LocalTransformDirty ) ;
4959 world. set_render_mesh (
5060 floor,
5161 RenderMesh {
@@ -63,6 +73,42 @@ impl State for ShadowsDemo {
6373 ) ;
6474 world. set_casts_shadow ( floor, CastsShadow ) ;
6575
76+ let wall = world. spawn_entities (
77+ LOCAL_TRANSFORM
78+ | LOCAL_TRANSFORM_DIRTY
79+ | GLOBAL_TRANSFORM
80+ | RENDER_MESH
81+ | MATERIAL
82+ | CASTS_SHADOW ,
83+ 1 ,
84+ ) [ 0 ] ;
85+ world. set_local_transform (
86+ wall,
87+ LocalTransform {
88+ translation : Vec3 :: new ( 0.0 , -3.0 , -10.0 ) ,
89+ rotation : Quat :: identity ( ) ,
90+ scale : Vec3 :: new ( 30.0 , 20.0 , 0.1 ) ,
91+ } ,
92+ ) ;
93+ world. set_global_transform ( wall, GlobalTransform ( nalgebra_glm:: Mat4 :: identity ( ) ) ) ;
94+ world. set_local_transform_dirty ( wall, LocalTransformDirty ) ;
95+ world. set_render_mesh (
96+ wall,
97+ RenderMesh {
98+ name : "Cube" . to_string ( ) ,
99+ } ,
100+ ) ;
101+ world. set_material (
102+ wall,
103+ Material {
104+ base_color : [ 0.7 , 0.6 , 0.5 , 1.0 ] ,
105+ roughness : 0.9 ,
106+ metallic : 0.0 ,
107+ ..Default :: default ( )
108+ } ,
109+ ) ;
110+ world. set_casts_shadow ( wall, CastsShadow ) ;
111+
66112 let torus = world. spawn_entities (
67113 LOCAL_TRANSFORM
68114 | LOCAL_TRANSFORM_DIRTY
@@ -84,6 +130,8 @@ impl State for ShadowsDemo {
84130 scale : Vec3 :: new ( 4.0 , 4.0 , 4.0 ) ,
85131 } ,
86132 ) ;
133+ world. set_global_transform ( torus, GlobalTransform ( nalgebra_glm:: Mat4 :: identity ( ) ) ) ;
134+ world. set_local_transform_dirty ( torus, LocalTransformDirty ) ;
87135 world. set_render_mesh (
88136 torus,
89137 RenderMesh {
@@ -109,6 +157,72 @@ impl State for ShadowsDemo {
109157 ) ;
110158 world. set_casts_shadow ( torus, CastsShadow ) ;
111159
160+ let torus_light_cube = world. spawn_entities (
161+ LOCAL_TRANSFORM | LOCAL_TRANSFORM_DIRTY | GLOBAL_TRANSFORM | RENDER_MESH | MATERIAL ,
162+ 1 ,
163+ ) [ 0 ] ;
164+ world. set_local_transform (
165+ torus_light_cube,
166+ LocalTransform {
167+ translation : Vec3 :: new ( 0.0 , -4.7 , 0.0 ) ,
168+ rotation : Quat :: identity ( ) ,
169+ scale : Vec3 :: new ( 0.5 , 0.5 , 0.5 ) ,
170+ } ,
171+ ) ;
172+ world. set_global_transform (
173+ torus_light_cube,
174+ GlobalTransform ( nalgebra_glm:: Mat4 :: identity ( ) ) ,
175+ ) ;
176+ world. set_local_transform_dirty ( torus_light_cube, LocalTransformDirty ) ;
177+ world. set_render_mesh (
178+ torus_light_cube,
179+ RenderMesh {
180+ name : "Cube" . to_string ( ) ,
181+ } ,
182+ ) ;
183+ world. set_material (
184+ torus_light_cube,
185+ Material {
186+ base_color : [ 1.0 , 0.8 , 0.6 , 1.0 ] ,
187+ emissive_factor : [ 2.0 , 1.6 , 1.2 ] ,
188+ roughness : 0.0 ,
189+ metallic : 0.0 ,
190+ unlit : true ,
191+ ..Default :: default ( )
192+ } ,
193+ ) ;
194+
195+ let torus_point_light = world. spawn_entities (
196+ LOCAL_TRANSFORM | LOCAL_TRANSFORM_DIRTY | GLOBAL_TRANSFORM | LIGHT ,
197+ 1 ,
198+ ) [ 0 ] ;
199+ world. set_local_transform (
200+ torus_point_light,
201+ LocalTransform {
202+ translation : Vec3 :: new ( 0.0 , -4.7 , 0.0 ) ,
203+ rotation : Quat :: identity ( ) ,
204+ scale : Vec3 :: new ( 1.0 , 1.0 , 1.0 ) ,
205+ } ,
206+ ) ;
207+ world. set_global_transform (
208+ torus_point_light,
209+ GlobalTransform ( nalgebra_glm:: Mat4 :: identity ( ) ) ,
210+ ) ;
211+ world. set_local_transform_dirty ( torus_point_light, LocalTransformDirty ) ;
212+ world. set_light (
213+ torus_point_light,
214+ Light {
215+ light_type : LightType :: Point ,
216+ color : Vec3 :: new ( 1.0 , 0.8 , 0.6 ) ,
217+ intensity : 10.0 ,
218+ range : 20.0 ,
219+ inner_cone_angle : 0.0 ,
220+ outer_cone_angle : 0.0 ,
221+ cast_shadows : true ,
222+ shadow_bias : 0.007 ,
223+ } ,
224+ ) ;
225+
112226 for _ in 0 ..18 {
113227 let x = rng. random_range ( -15.0 ..15.0 ) ;
114228 let y = rng. random_range ( -11.0 ..11.0 ) ;
@@ -134,6 +248,7 @@ impl State for ShadowsDemo {
134248 scale : Vec3 :: new ( scale, scale, scale) ,
135249 } ,
136250 ) ;
251+ world. set_local_transform_dirty ( sphere, LocalTransformDirty ) ;
137252 world. set_render_mesh (
138253 sphere,
139254 RenderMesh {
@@ -160,23 +275,20 @@ impl State for ShadowsDemo {
160275 LOCAL_TRANSFORM | LOCAL_TRANSFORM_DIRTY | GLOBAL_TRANSFORM | LIGHT ,
161276 1 ,
162277 ) [ 0 ] ;
163- world. set_local_transform (
164- light,
165- LocalTransform {
166- translation : Vec3 :: new ( 0.0 , 100.0 , 0.0 ) ,
167- rotation : nalgebra_glm:: quat_angle_axis (
168- -std:: f32:: consts:: FRAC_PI_2 ,
169- & Vec3 :: x_axis ( ) ,
170- ) ,
171- scale : Vec3 :: new ( 1.0 , 1.0 , 1.0 ) ,
172- } ,
173- ) ;
278+ let light_transform = LocalTransform {
279+ translation : Vec3 :: new ( 0.0 , 100.0 , 0.0 ) ,
280+ rotation : nalgebra_glm:: quat_angle_axis ( -std:: f32:: consts:: FRAC_PI_2 , & Vec3 :: x_axis ( ) ) ,
281+ scale : Vec3 :: new ( 1.0 , 1.0 , 1.0 ) ,
282+ } ;
283+ world. set_local_transform ( light, light_transform) ;
284+ world. set_global_transform ( light, GlobalTransform ( light_transform. as_matrix ( ) ) ) ;
285+ world. set_local_transform_dirty ( light, LocalTransformDirty ) ;
174286 world. set_light (
175287 light,
176288 Light {
177289 light_type : LightType :: Directional ,
178290 color : Vec3 :: new ( 1.0 , 1.0 , 1.0 ) ,
179- intensity : 3 .0,
291+ intensity : 1 .0,
180292 range : 100.0 ,
181293 inner_cone_angle : 0.0 ,
182294 outer_cone_angle : 0.0 ,
@@ -187,35 +299,85 @@ impl State for ShadowsDemo {
187299
188300 self . resources . light_entity = Some ( light) ;
189301
302+ let light_cone = world. spawn_entities (
303+ LOCAL_TRANSFORM | LOCAL_TRANSFORM_DIRTY | GLOBAL_TRANSFORM | RENDER_MESH | MATERIAL ,
304+ 1 ,
305+ ) [ 0 ] ;
306+ world. set_local_transform (
307+ light_cone,
308+ LocalTransform {
309+ translation : Vec3 :: new ( 0.0 , 100.0 , 0.0 ) ,
310+ rotation : nalgebra_glm:: quat_angle_axis (
311+ -std:: f32:: consts:: FRAC_PI_2 ,
312+ & Vec3 :: x_axis ( ) ,
313+ ) ,
314+ scale : Vec3 :: new ( 3.0 , 3.0 , 3.0 ) ,
315+ } ,
316+ ) ;
317+ world. set_global_transform ( light_cone, GlobalTransform ( nalgebra_glm:: Mat4 :: identity ( ) ) ) ;
318+ world. set_local_transform_dirty ( light_cone, LocalTransformDirty ) ;
319+ world. set_render_mesh (
320+ light_cone,
321+ RenderMesh {
322+ name : "Cone" . to_string ( ) ,
323+ } ,
324+ ) ;
325+ world. set_material (
326+ light_cone,
327+ Material {
328+ base_color : [ 1.0 , 1.0 , 0.8 , 1.0 ] ,
329+ emissive_factor : [ 1.0 , 1.0 , 0.8 ] ,
330+ roughness : 0.0 ,
331+ metallic : 0.0 ,
332+ unlit : true ,
333+ ..Default :: default ( )
334+ } ,
335+ ) ;
336+
337+ self . resources . light_cone_entity = Some ( light_cone) ;
338+
190339 let camera_position = Vec3 :: new ( 0.0 , 10.0 , 20.0 ) ;
191340 let camera = spawn_camera ( world, camera_position, "Main Camera" . to_string ( ) ) ;
341+ if let Some ( camera_transform) = world. get_local_transform ( camera) {
342+ world. set_global_transform ( camera, GlobalTransform ( camera_transform. as_matrix ( ) ) ) ;
343+ }
192344 world. resources . active_camera = Some ( camera) ;
193- }
194345
195- fn run_systems ( & mut self , world : & mut World ) {
196- let delta = world. resources . window . timing . delta_time ;
197- self . resources . time += delta;
198-
199- if let Some ( light_entity) = self . resources . light_entity {
200- if let Some ( mut transform) = world. get_local_transform ( light_entity) . cloned ( ) {
201- let x = 50.0 * self . resources . time . sin ( ) ;
202- let z = 50.0 * self . resources . time . cos ( ) ;
203- transform. translation . x = x;
204- transform. translation . z = z;
346+ let flashlight = world. spawn_entities (
347+ LOCAL_TRANSFORM | LOCAL_TRANSFORM_DIRTY | GLOBAL_TRANSFORM | LIGHT | PARENT ,
348+ 1 ,
349+ ) [ 0 ] ;
205350
206- let target = Vec3 :: zeros ( ) ;
207- let direction = ( target - transform. translation ) . normalize ( ) ;
351+ let flashlight_transform = LocalTransform {
352+ translation : Vec3 :: new ( 0.5 , -1.2 , 0.3 ) ,
353+ rotation : Quat :: identity ( ) ,
354+ scale : Vec3 :: new ( 1.0 , 1.0 , 1.0 ) ,
355+ } ;
356+ world. set_local_transform ( flashlight, flashlight_transform) ;
357+ world. set_parent ( flashlight, Parent ( Some ( camera) ) ) ;
358+ world. set_local_transform_dirty ( flashlight, LocalTransformDirty ) ;
359+ world. set_light (
360+ flashlight,
361+ Light {
362+ light_type : LightType :: Spot ,
363+ color : Vec3 :: new ( 1.0 , 1.0 , 0.9 ) ,
364+ intensity : 15.0 ,
365+ range : 100.0 ,
366+ inner_cone_angle : 0.15 ,
367+ outer_cone_angle : 0.4 ,
368+ cast_shadows : true ,
369+ shadow_bias : 0.007 ,
370+ } ,
371+ ) ;
208372
209- let pitch = direction. y . asin ( ) ;
210- let yaw = direction. z . atan2 ( direction. x ) ;
373+ self . resources . flashlight_entity = Some ( flashlight) ;
211374
212- transform. rotation = nalgebra_glm :: quat_angle_axis ( yaw , & Vec3 :: y ( ) )
213- * nalgebra_glm :: quat_angle_axis ( pitch , & Vec3 :: x ( ) ) ;
375+ nightshade :: ecs :: transform:: systems :: run_systems ( world ) ;
376+ }
214377
215- world. set_local_transform ( light_entity, transform) ;
216- world. set_local_transform_dirty ( light_entity, LocalTransformDirty ) ;
217- }
218- }
378+ fn run_systems ( & mut self , world : & mut World ) {
379+ let delta = world. resources . window . timing . delta_time ;
380+ self . resources . time += delta;
219381
220382 for ( sphere_entity, _initial_y, velocity) in & mut self . resources . spheres {
221383 if let Some ( mut transform) = world. get_local_transform ( * sphere_entity) . cloned ( ) {
@@ -252,7 +414,66 @@ impl State for ShadowsDemo {
252414 }
253415 }
254416
417+ if let Some ( light_entity) = self . resources . light_entity {
418+ let cycle_speed = 0.2 ;
419+ let angle = self . resources . time * cycle_speed;
420+ let radius = 25.0 ;
421+
422+ let light_x = angle. sin ( ) * radius;
423+ let light_y = angle. cos ( ) * radius;
424+ let light_position = Vec3 :: new ( light_x, light_y, 0.0 ) ;
425+
426+ let scene_center = Vec3 :: new ( 0.0 , 0.0 , 0.0 ) ;
427+ let light_direction_toward_scene = ( scene_center - light_position) . normalize ( ) ;
428+
429+ let up = if light_direction_toward_scene. y . abs ( ) > 0.99 {
430+ Vec3 :: new ( 1.0 , 0.0 , 0.0 )
431+ } else {
432+ Vec3 :: new ( 0.0 , 1.0 , 0.0 )
433+ } ;
434+
435+ let light_rotation = nalgebra_glm:: quat_look_at_rh ( & light_direction_toward_scene, & up) ;
436+
437+ let transform = LocalTransform {
438+ translation : light_position,
439+ rotation : light_rotation,
440+ scale : Vec3 :: new ( 1.0 , 1.0 , 1.0 ) ,
441+ } ;
442+
443+ world. set_local_transform ( light_entity, transform) ;
444+ world. set_local_transform_dirty ( light_entity, LocalTransformDirty ) ;
445+
446+ if let Some ( light_cone_entity) = self . resources . light_cone_entity {
447+ let cone_rotation = light_rotation
448+ * nalgebra_glm:: quat_angle_axis ( std:: f32:: consts:: FRAC_PI_2 , & Vec3 :: x_axis ( ) ) ;
449+ let cone_transform = LocalTransform {
450+ translation : light_position,
451+ rotation : cone_rotation,
452+ scale : Vec3 :: new ( 3.0 , 3.0 , 3.0 ) ,
453+ } ;
454+ world. set_local_transform ( light_cone_entity, cone_transform) ;
455+ world. set_local_transform_dirty ( light_cone_entity, LocalTransformDirty ) ;
456+ }
457+ }
458+
255459 escape_key_exit_system ( world) ;
256460 fly_camera_system ( world) ;
461+ nightshade:: ecs:: transform:: systems:: run_systems ( world) ;
462+ }
463+
464+ fn on_keyboard_input ( & mut self , world : & mut World , key_code : KeyCode , key_state : KeyState ) {
465+ if matches ! ( ( key_code, key_state) , ( KeyCode :: KeyF , KeyState :: Pressed ) ) {
466+ self . resources . flashlight_enabled = !self . resources . flashlight_enabled ;
467+ if let Some ( flashlight_entity) = self . resources . flashlight_entity {
468+ if let Some ( mut light) = world. get_light ( flashlight_entity) . cloned ( ) {
469+ light. intensity = if self . resources . flashlight_enabled {
470+ 15.0
471+ } else {
472+ 0.0
473+ } ;
474+ world. set_light ( flashlight_entity, light) ;
475+ }
476+ }
477+ }
257478 }
258479}
0 commit comments