@@ -11,7 +11,7 @@ use genmesh::{
1111 generators:: { IndexedPolygon , SharedVertex } ,
1212 Triangulate ,
1313} ;
14- use glam:: { Mat4 , UVec2 , Vec4 , Vec4Swizzles } ;
14+ use glam:: { Mat4 , UVec2 , Vec3 , Vec4 , Vec4Swizzles } ;
1515use windows:: Win32 :: Graphics :: {
1616 Direct3D11 :: {
1717 ID3D11Buffer , ID3D11DepthStencilState , D3D11_BIND_INDEX_BUFFER , D3D11_BIND_VERTEX_BUFFER ,
@@ -174,7 +174,7 @@ impl LightRenderer {
174174 debug_label : String ,
175175 ) -> anyhow:: Result < Self > {
176176 Ok ( Self {
177- projection_matrix : light. light_to_world ,
177+ projection_matrix : light. light_space_transform ,
178178 technique_shading : asset_manager. get_or_load_technique ( light. technique_shading ) ,
179179 _technique_volumetrics : asset_manager
180180 . get_or_load_technique ( light. technique_volumetrics ) ,
@@ -193,7 +193,7 @@ impl LightRenderer {
193193 debug_label : String ,
194194 ) -> anyhow:: Result < Self > {
195195 Ok ( Self {
196- projection_matrix : light. light_to_world ,
196+ projection_matrix : light. light_space_transform ,
197197 technique_shading : asset_manager. get_or_load_technique ( light. technique_shading ) ,
198198 technique_shading_shadowing : Some (
199199 asset_manager. get_or_load_technique ( light. technique_shading_shadowing ) ,
@@ -278,27 +278,28 @@ pub fn draw_light_system(renderer: &Renderer, scene: &mut Scene) {
278278 return ;
279279 } ;
280280
281- let transform_relative = Transform {
282- translation : transform. translation - view. position . xyz ( ) ,
283- // translation: Vec3::ZERO,
284- ..* transform
285- } ;
281+ let local_to_world_scaled = transform. local_to_world ( ) * light. light_space_transform ;
282+ let view_translation_inverse_mat4 = Mat4 :: from_translation ( -view. position . xyz ( ) ) ;
283+ let local_to_world_relative =
284+ view_translation_inverse_mat4 * transform. local_to_world ( ) ;
286285
287- let transform_mat = transform_relative. local_to_world ( ) ;
288- let transform_mat_scaled = transform. local_to_world ( ) * light. light_to_world ;
286+ let ( min, max) = compute_light_bounds ( light. light_space_transform ) ;
287+ let light_local_to_world =
288+ compute_light_local_to_world ( transform. local_to_world ( ) , min, max) ;
289289
290- externs. simple_geometry = Some ( externs:: SimpleGeometry {
291- transform : view. world_to_projective * transform_mat_scaled,
292- } ) ;
293290 let existing_deflight = externs. deferred_light . as_ref ( ) . cloned ( ) . unwrap_or_default ( ) ;
294291 externs. deferred_light = Some ( externs:: DeferredLight {
295- // TODO(cohae): Used for transforming projective textures (see lamps in Altar of Reflection)
296- unk40 : Transform :: from_translation ( view . position . xyz ( ) ) . local_to_world ( ) ,
297- unk80 : transform_mat ,
292+ unk40 : ( view_translation_inverse_mat4 * light_local_to_world ) . inverse ( ) ,
293+ unk80 : local_to_world_relative ,
294+
298295 unk100 : light. unk50 ,
299296
300297 ..existing_deflight
301298 } ) ;
299+
300+ externs. simple_geometry = Some ( externs:: SimpleGeometry {
301+ transform : view. world_to_projective * local_to_world_scaled,
302+ } ) ;
302303 }
303304
304305 light_renderer. draw ( renderer, false ) ;
@@ -330,18 +331,20 @@ pub fn draw_light_system(renderer: &Renderer, scene: &mut Scene) {
330331 ..* transform
331332 } ;
332333
333- let transform_mat = transform_relative. local_to_world ( ) ;
334- let transform_mat_scaled = transform. local_to_world ( ) * light. light_to_world ;
334+ let local_to_world_scaled = transform. local_to_world ( ) * light. light_space_transform ;
335+ let view_translation_inverse_mat4 = Mat4 :: from_translation ( -view. position . xyz ( ) ) ;
336+ let local_to_world_relative =
337+ view_translation_inverse_mat4 * transform. local_to_world ( ) ;
335338
336- externs . simple_geometry = Some ( externs :: SimpleGeometry {
337- transform : view . world_to_projective * transform_mat_scaled ,
338- } ) ;
339+ let ( min , max ) = compute_light_bounds ( light . light_space_transform ) ;
340+ let light_local_to_world =
341+ compute_light_local_to_world ( transform . local_to_world ( ) , min , max ) ;
339342
340343 let existing_deflight = externs. deferred_light . as_ref ( ) . cloned ( ) . unwrap_or_default ( ) ;
341344 externs. deferred_light = Some ( externs:: DeferredLight {
342- // TODO(cohae): Used for transforming projective textures (see lamps in Altar of Reflection)
343- unk40 : Transform :: from_translation ( view . position . xyz ( ) ) . local_to_world ( ) ,
344- unk80 : transform_mat ,
345+ unk40 : ( view_translation_inverse_mat4 * light_local_to_world ) . inverse ( ) ,
346+ unk80 : local_to_world_relative ,
347+
345348 unk100 : light. unk50 ,
346349 // unk110: 1.0,
347350 // unk114: 2000.0,
@@ -351,6 +354,10 @@ pub fn draw_light_system(renderer: &Renderer, scene: &mut Scene) {
351354 ..existing_deflight
352355 } ) ;
353356
357+ externs. simple_geometry = Some ( externs:: SimpleGeometry {
358+ transform : view. world_to_projective * local_to_world_scaled,
359+ } ) ;
360+
354361 if let Some ( shadowmap) = shadowmap {
355362 // TODO(cohae): Unknown what this texture is supposed to be. VS loads the first pixel and uses it as multiplier for the shadowmap UVs
356363 renderer
@@ -557,3 +564,71 @@ pub fn update_shadowrenderer_system(
557564 }
558565 }
559566}
567+
568+ fn compute_light_bounds ( light_space_transform : Mat4 ) -> ( Vec3 , Vec3 ) {
569+ let mut points = [
570+ Vec3 :: new ( -1.0 , -1.0 , -1.0 ) ,
571+ Vec3 :: new ( -1.0 , -1.0 , 1.0 ) ,
572+ Vec3 :: new ( -1.0 , 1.0 , -1.0 ) ,
573+ Vec3 :: new ( -1.0 , 1.0 , 1.0 ) ,
574+ Vec3 :: new ( 1.0 , -1.0 , -1.0 ) ,
575+ Vec3 :: new ( 1.0 , -1.0 , 1.0 ) ,
576+ Vec3 :: new ( 1.0 , 1.0 , -1.0 ) ,
577+ Vec3 :: new ( 1.0 , 1.0 , 1.0 ) ,
578+ ] ;
579+
580+ for point in & mut points {
581+ let p = light_space_transform. mul_vec4 ( point. extend ( 1.0 ) ) ;
582+ let point_w_abs = ( -p. wwww ( ) ) . abs ( ) ;
583+ * point = Vec4 :: select (
584+ point_w_abs. cmpge ( Vec4 :: splat ( 0.0001 ) ) ,
585+ p / p. wwww ( ) ,
586+ Vec4 :: W ,
587+ )
588+ . truncate ( ) ;
589+ }
590+
591+ points
592+ . iter ( )
593+ . fold ( ( Vec3 :: MAX , Vec3 :: MIN ) , |( min, max) , & point| {
594+ ( min. min ( point) , max. max ( point) )
595+ } )
596+ }
597+
598+ fn compute_light_local_to_world ( node_local_to_world : Mat4 , min : Vec3 , max : Vec3 ) -> Mat4 {
599+ let bounds_center = min. midpoint ( max) ;
600+ let bounds_half_extents = ( max - min) / 2.0 ;
601+
602+ // First matrix operation ("mat"):
603+ // Each column is computed by scaling one of node_local_to_world’s axes by the corresponding component of bounds_half_extents,
604+ // except for the w-axis which is a linear combination of the x, y, and z axes plus the original w-axis.
605+ let mat = Mat4 {
606+ x_axis : node_local_to_world. x_axis * bounds_half_extents. x ,
607+ y_axis : node_local_to_world. y_axis * bounds_half_extents. y ,
608+ z_axis : node_local_to_world. z_axis * bounds_half_extents. z ,
609+ w_axis : node_local_to_world. x_axis * bounds_center. x
610+ + node_local_to_world. y_axis * bounds_center. y
611+ + node_local_to_world. z_axis * bounds_center. z
612+ + node_local_to_world. w_axis ,
613+ } ;
614+
615+ // Second matrix operation ("mat_scaled"):
616+ // Scale the x, y, and z axes by 2, and subtract all three from the w-axis.
617+ let mat_scaled = Mat4 {
618+ x_axis : mat. x_axis * 2.0 ,
619+ y_axis : mat. y_axis * 2.0 ,
620+ z_axis : mat. z_axis * 2.0 ,
621+ w_axis : mat. w_axis - mat. x_axis - mat. y_axis - mat. z_axis ,
622+ } ;
623+
624+ // Third matrix operation (computing light_local_to_world):
625+ // Rearrange the columns of mat_scaled: swap the x and z axes, leaving y and w unchanged.
626+ let light_local_to_world = Mat4 {
627+ x_axis : mat_scaled. z_axis ,
628+ y_axis : mat_scaled. y_axis ,
629+ z_axis : mat_scaled. x_axis ,
630+ w_axis : mat_scaled. w_axis ,
631+ } ;
632+
633+ light_local_to_world
634+ }
0 commit comments