fix(render): use view-dependent sky fog color
Docs Deploy / Build and Deploy MkDocs (push) Successful in 40s
Docs Deploy / Build and Deploy MkDocs (push) Successful in 40s
This commit is contained in:
3 files changed
+55
-13
No files matched your search
@@ -3468,7 +3468,11 @@ impl DynamicEnvironment {
|
|||||||
target.active = source.active;
|
target.active = source.active;
|
||||||
}
|
}
|
||||||
uniforms.lighting_floor = sky_frame.lighting_floor;
|
uniforms.lighting_floor = sky_frame.lighting_floor;
|
||||||
uniforms.fog_color = sky_frame.fog.color;
|
let fog_rgb = sky_frame
|
||||||
|
.screen_gradient(camera.native_sky_heading(), [0.0; 3])
|
||||||
|
.color
|
||||||
|
.rgba();
|
||||||
|
uniforms.fog_color = [fog_rgb[0], fog_rgb[1], fog_rgb[2]];
|
||||||
uniforms.fog_start = sky_frame.fog.start.max(0.0);
|
uniforms.fog_start = sky_frame.fog.start.max(0.0);
|
||||||
uniforms.fog_end = sky_frame.fog.end.max(uniforms.fog_start);
|
uniforms.fog_end = sky_frame.fog.end.max(uniforms.fog_start);
|
||||||
uniforms.camera_position = camera.position;
|
uniforms.camera_position = camera.position;
|
||||||
@@ -7901,6 +7905,37 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn captured_native_camera_uses_view_dependent_sky_fog_color() {
|
||||||
|
use fparkan_fx::atmosphere::{PackedColor, SkySample, SKY_COLOR_COUNT};
|
||||||
|
|
||||||
|
// Compact camera fields from the native 1493.337-second AutoDemo capture.
|
||||||
|
let capture = parse_legacy_camera_capture(
|
||||||
|
br#"{"schema":"fparkan-legacy-camera-v1","render_input_usable":true,"parented_camera":true,"effective_world_matrix_space":"world","effective_world_matrix_words":[1052770830,1064129158,991881820,1141874407,3211610778,1052772554,3144770972,1145115441,3146624790,3127057462,1065352580,1087889619,0,0,0,1065353216],"selector0_words":[1063123992,3204380634,996787387,3130169600,1056894806,1063125889,990301923,3129510813,3146181515,3070164857,1065352633,1080608413,0,0,0,1065353216],"viewport":[0,0,1280,1024],"near_plane":5.0,"far_plane":700.0,"field_of_view_radians":1.3,"atmosphere_seconds":1493.337}"#,
|
||||||
|
)
|
||||||
|
.expect("valid native camera fixture");
|
||||||
|
let camera = capture.preview_camera_frame().expect("valid camera frame");
|
||||||
|
|
||||||
|
let mut colors = [PackedColor(0xFF00_0000); SKY_COLOR_COUNT];
|
||||||
|
colors[..4].copy_from_slice(&[
|
||||||
|
PackedColor(0xFF38_3864),
|
||||||
|
PackedColor(0xFF38_3864),
|
||||||
|
PackedColor(0xFF40_4064),
|
||||||
|
PackedColor(0xFF38_3864),
|
||||||
|
]);
|
||||||
|
let sample = SkySample {
|
||||||
|
colors,
|
||||||
|
values: [0.0; 2],
|
||||||
|
packed: [PackedColor(0); 2],
|
||||||
|
};
|
||||||
|
let fog_color =
|
||||||
|
fparkan_fx::sky::screen_gradient_frame(&sample, camera.native_sky_heading(), [0.0; 3])
|
||||||
|
.color;
|
||||||
|
|
||||||
|
assert_eq!(capture.atmosphere_seconds, Some(1493.337));
|
||||||
|
assert_eq!(fog_color, PackedColor(0xFF3E_3E64));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sky_normals_keep_native_signed_byte_scale_without_renormalizing() {
|
fn sky_normals_keep_native_signed_byte_scale_without_renormalizing() {
|
||||||
assert_eq!(sky_normal([-128, 127, -64]), [-1.0, 127.0 / 128.0, -0.5]);
|
assert_eq!(sky_normal([-128, 127, -64]), [-1.0, 127.0 / 128.0, -0.5]);
|
||||||
|
|||||||
@@ -957,12 +957,14 @@ impl fmt::Display for SkyUpdateError {
|
|||||||
|
|
||||||
impl std::error::Error for SkyUpdateError {}
|
impl std::error::Error for SkyUpdateError {}
|
||||||
|
|
||||||
/// Fog values sent by the original `CSky` update.
|
/// Distance and ambient-light values derived from an original `CSky` sample.
|
||||||
|
///
|
||||||
|
/// The renderer's `D3DRS_FOGCOLOR` is view-dependent: it is interpolated from
|
||||||
|
/// `SkySample::colors[0..4]` using the native sky heading. It is not this
|
||||||
|
/// sample-only frame value.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct FogFrame {
|
pub struct FogFrame {
|
||||||
/// Normalized RGB fog color from `SkySample::packed[1]`.
|
/// Native global lighting floor from `SkySample::packed[1]`.
|
||||||
pub color: [f32; 3],
|
|
||||||
/// Native global lighting floor from the same sampled RGB state.
|
|
||||||
///
|
///
|
||||||
/// `CShade` merges this vector with the material lighting accumulator by
|
/// `CShade` merges this vector with the material lighting accumulator by
|
||||||
/// taking the per-channel maximum before the shader receives the result.
|
/// taking the per-channel maximum before the shader receives the result.
|
||||||
@@ -980,10 +982,8 @@ impl FogFrame {
|
|||||||
let start = finite_or_zero(sample.values[0]) * FOG_DISTANCE_SCALE;
|
let start = finite_or_zero(sample.values[0]) * FOG_DISTANCE_SCALE;
|
||||||
let end = finite_or_zero(sample.values[1]) * FOG_DISTANCE_SCALE;
|
let end = finite_or_zero(sample.values[1]) * FOG_DISTANCE_SCALE;
|
||||||
let rgba = sample.packed[1].rgba();
|
let rgba = sample.packed[1].rgba();
|
||||||
let color = [rgba[0], rgba[1], rgba[2]];
|
|
||||||
Self {
|
Self {
|
||||||
color,
|
lighting_floor: [rgba[0], rgba[1], rgba[2]],
|
||||||
lighting_floor: color,
|
|
||||||
start,
|
start,
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
@@ -1845,12 +1845,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fog_uses_original_scale_and_packed_rgb() {
|
fn fog_distances_use_original_scale_and_floor_uses_packed_rgb() {
|
||||||
let frame = fog_frame(&sample());
|
let frame = fog_frame(&sample());
|
||||||
assert_eq!(frame.start, 700.0);
|
assert_eq!(frame.start, 700.0);
|
||||||
assert_eq!(frame.end, 1_400.0);
|
assert_eq!(frame.end, 1_400.0);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
frame.color,
|
frame.lighting_floor,
|
||||||
[
|
[
|
||||||
0x11 as f32 / 255.0,
|
0x11 as f32 / 255.0,
|
||||||
0x22 as f32 / 255.0,
|
0x22 as f32 / 255.0,
|
||||||
@@ -1945,11 +1945,10 @@ mod tests {
|
|||||||
|
|
||||||
let mut atmosphere = atmosphere(true);
|
let mut atmosphere = atmosphere(true);
|
||||||
atmosphere.sky.colors[12] = PackedColor(0xFF12_3456);
|
atmosphere.sky.colors[12] = PackedColor(0xFF12_3456);
|
||||||
let (lighting_floor, fog_color, sprites_have_native_uv) = {
|
let (lighting_floor, sprites_have_native_uv) = {
|
||||||
let frame = system.update(&atmosphere, 10.0).expect("sky update");
|
let frame = system.update(&atmosphere, 10.0).expect("sky update");
|
||||||
(
|
(
|
||||||
frame.lighting_floor,
|
frame.lighting_floor,
|
||||||
frame.fog.color,
|
|
||||||
frame
|
frame
|
||||||
.sprites
|
.sprites
|
||||||
.iter()
|
.iter()
|
||||||
@@ -1969,7 +1968,8 @@ mod tests {
|
|||||||
positions
|
positions
|
||||||
);
|
);
|
||||||
assert_eq!(system.mesh().vertices[0].color, PackedColor(0xFF12_3456));
|
assert_eq!(system.mesh().vertices[0].color, PackedColor(0xFF12_3456));
|
||||||
assert_eq!(lighting_floor, fog_color);
|
let packed = atmosphere.sky.packed[1].rgba();
|
||||||
|
assert_eq!(lighting_floor, [packed[0], packed[1], packed[2]]);
|
||||||
assert!(sprites_have_native_uv);
|
assert!(sprites_have_native_uv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,13 @@ sky.wea
|
|||||||
backend разрешает архив и имя звука. Это позволяет одной и той же модели
|
backend разрешает архив и имя звука. Это позволяет одной и той же модели
|
||||||
погоды работать в preview и в игровом цикле.
|
погоды работать в preview и в игровом цикле.
|
||||||
|
|
||||||
|
Цвета неба, ambient lighting и fog renderer-а используют разные поля того же
|
||||||
|
`sky.ske` sample. `SkySample::packed[1]` задаёт глобальный lighting floor;
|
||||||
|
`CShade` объединяет его с material lighting по поканальному максимуму.
|
||||||
|
`D3DRS_FOGCOLOR` (`0x22`) зависит от направления камеры и интерполируется из
|
||||||
|
`SkySample::colors[0..4]` по native sky heading. Значения `sky.values[0..1]`
|
||||||
|
продолжают задавать fog start/end, масштабируемые на 700.
|
||||||
|
|
||||||
## Входы и границы
|
## Входы и границы
|
||||||
|
|
||||||
Для расписания используется такой вызов:
|
Для расписания используется такой вызов:
|
||||||
|
|||||||
Reference in new issue
Block a user