fix(render): use native squared distance for vertex fog
Docs Deploy / Build and Deploy MkDocs (push) Successful in 36s
Docs Deploy / Build and Deploy MkDocs (push) Successful in 36s
This commit is contained in:
7 files changed
+75
-8
No files matched your search
@@ -130,12 +130,13 @@ float native_specular_power(float cosine, float power) {
|
||||
}
|
||||
|
||||
float native_fog_factor(vec3 world_position) {
|
||||
float fog_span = frame.fog_distances.y - frame.fog_distances.x;
|
||||
float distance_to_camera = distance(world_position, frame.camera_position.xyz);
|
||||
if (fog_span <= 0.000001 || distance_to_camera <= frame.fog_distances.x) {
|
||||
float fog_span_squared = frame.fog_distances.w - frame.fog_distances.z;
|
||||
vec3 to_camera = world_position - frame.camera_position.xyz;
|
||||
float distance_squared = dot(to_camera, to_camera);
|
||||
if (fog_span_squared <= 0.000001 || distance_squared <= frame.fog_distances.z) {
|
||||
return 0.0;
|
||||
}
|
||||
return clamp((distance_to_camera - frame.fog_distances.x) / fog_span, 0.0, 1.0);
|
||||
return clamp((distance_squared - frame.fog_distances.z) / fog_span_squared, 0.0, 1.0);
|
||||
}
|
||||
|
||||
vec3 normalized_or(vec3 value, vec3 fallback) {
|
||||
|
||||
Binary file not shown.
@@ -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],
|
||||
@@ -874,6 +887,31 @@ mod static_mesh_tests {
|
||||
assert_eq!(mesh.validate(), Ok(()));
|
||||
}
|
||||
|
||||
#[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 {
|
||||
|
||||
Reference in new issue
Block a user