diff options
| author | Valentin Popov <valentin@popov.link> | 2026-10-31 18:13:43 +0300 |
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2026-10-31 18:13:43 +0300 |
| commit | 9f643149a69a149612cffd65a953527630e95647 (patch) | |
| tree | 16954a813dc0b7a870f75f2e1f113041676d0837 /adapters/fparkan-render-vulkan/src | |
| parent | 108a04b70e0cd5032d417cc7fd00cec2a385246b (diff) | |
| download | fparkan-9f643149a69a149612cffd65a953527630e95647.tar.xz fparkan-9f643149a69a149612cffd65a953527630e95647.zip | |
fix(render): use native squared distance for vertex fog
Diffstat (limited to 'adapters/fparkan-render-vulkan/src')
| -rw-r--r-- | adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs b/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs index 278243b..0996fa1 100644 --- a/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs +++ b/adapters/fparkan-render-vulkan/src/ffi/smoke_types.rs @@ -284,6 +284,9 @@ impl VulkanFrameUniforms { .chain([self.fog_start, self.fog_end]) .chain(self.camera_position) .all(f32::is_finite) + && (self.fog_end <= self.fog_start + || ((self.fog_start * self.fog_start).is_finite() + && (self.fog_end * self.fog_end).is_finite())) } /// Serializes one frame slot in the exact `std140` member order. @@ -344,7 +347,17 @@ impl VulkanFrameUniforms { self.fog_color[2], 0.0, ]); - values[84..88].copy_from_slice(&[self.fog_start, self.fog_end, 0.0, 0.0]); + let squared_fog_range = if self.fog_end > self.fog_start { + [self.fog_start * self.fog_start, self.fog_end * self.fog_end] + } else { + [0.0; 2] + }; + values[84..88].copy_from_slice(&[ + self.fog_start, + self.fog_end, + squared_fog_range[0], + squared_fog_range[1], + ]); values[88..92].copy_from_slice(&[ self.camera_position[0], self.camera_position[1], @@ -875,6 +888,31 @@ mod static_mesh_tests { } #[test] + fn fog_uniforms_match_live_native_squared_distance_range() { + // Terrain ShadeIndexedStrided: far=0x442389e6, far²=0x48d0f1ca; + // distance²=0x47707b04 gives visibility=0x3f5b2b94. + let frame = VulkanFrameUniforms { + fog_start: 0.0, + fog_end: f32::from_bits(0x4423_89e6), + ..Default::default() + }; + assert!(frame.is_finite()); + let bytes = frame.to_ne_bytes(); + let read = |offset| f32::from_ne_bytes(bytes[offset..offset + 4].try_into().unwrap()); + assert_eq!(read(344), 0.0); + assert_eq!(read(348).to_bits(), 0x48d0_f1ca); + let visibility = 1.0 - (f32::from_bits(0x4770_7b04) - read(344)) / (read(348) - read(344)); + assert!((visibility - f32::from_bits(0x3f5b_2b94)).abs() < 1.0e-6); + assert!(VulkanFrameUniforms::default().is_finite()); + assert!(!VulkanFrameUniforms { + fog_start: 0.0, + fog_end: f32::MAX, + ..frame + } + .is_finite()); + } + + #[test] fn static_camera_composes_recovered_d3d7_view_before_projection() { let transform = RawCameraTransform { words: [ |
