Skip to content

Commit 902a504

Browse files
committed
renderer: Light matrix fixes
1 parent cde4ea8 commit 902a504

File tree

6 files changed

+122
-31
lines changed

6 files changed

+122
-31
lines changed

.zed/settings.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Folder-specific settings
2+
//
3+
// For a full list of overridable settings, and general information on folder-specific settings,
4+
// see the documentation: https://zed.dev/docs/configuring-zed#settings-files
5+
{
6+
"lsp": {
7+
"rust-analyzer": {
8+
"initialization_options": {
9+
"cargo": {
10+
"target": "x86_64-pc-windows-msvc"
11+
}
12+
}
13+
}
14+
}
15+
}

crates/alkahest-data/src/map.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ pub struct SLight {
408408
pub unk30: Vec4,
409409
pub unk40: [u32; 4],
410410
pub unk50: Vec4,
411-
pub light_to_world: Mat4,
411+
pub light_space_transform: Mat4,
412412
pub unka0: u32,
413413
pub unka4: u32,
414414
pub unka8: u32,
@@ -439,7 +439,7 @@ pub struct SShadowingLight {
439439
pub unk30: Vec4,
440440
pub unk40: [u32; 4],
441441
pub unk50: Vec4,
442-
pub light_to_world: Mat4,
442+
pub light_space_transform: Mat4,
443443
pub unka0: u32,
444444
pub unka4: u32,
445445
pub unka8: u32,

crates/alkahest-renderer/src/ecs/render/light.rs

Lines changed: 99 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -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};
1515
use 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+
}

crates/alkahest-renderer/src/loaders/map.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,7 @@ fn load_datatable_into_scene<R: Read + Seek>(
798798
))
799799
.enumerate()
800800
{
801-
let shape = LightShape::from_volume_matrix(light.light_to_world);
801+
let shape = LightShape::from_volume_matrix(light.light_space_transform);
802802
let transform = Transform {
803803
translation: transform.translation.xyz(),
804804
rotation: transform.rotation,
@@ -854,7 +854,7 @@ fn load_datatable_into_scene<R: Read + Seek>(
854854
renderer.settings.shadow_quality.resolution(),
855855
)?;
856856

857-
let bb = Aabb::from_projection_matrix(light.light_to_world);
857+
let bb = Aabb::from_projection_matrix(light.light_space_transform);
858858

859859
spawn_data_entity(
860860
scene,

crates/alkahest/lib/iron.lib

2 KB
Binary file not shown.

crates/alkahest/src/gui/sodi.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use std::time::Instant;
22

33
use alkahest_renderer::{
44
icons::{ICON_CAMERA_OFF_OUTLINE, ICON_EYE_LOCK_OUTLINE},
5-
resources::AppResources, util::FloatExt,
5+
resources::AppResources,
6+
util::FloatExt,
67
};
78
use egui::*;
89
use windows_registry::CURRENT_USER;
@@ -33,7 +34,7 @@ impl Sodi {
3334
Err(e) => {
3435
error!("Failed to check SODI acceptance: {e:?}");
3536
false
36-
},
37+
}
3738
}
3839
}
3940
}
@@ -99,7 +100,7 @@ impl GuiView for Sodi {
99100
.color(Color32::WHITE)
100101
.size(128.0),
101102
);
102-
103+
103104
ui.weak(format!("{ICON_CAMERA_OFF_OUTLINE} Capturing disabled"));
104105
});
105106

0 commit comments

Comments
 (0)