Revert "feat(sky): the night sky wheels with the Dereth clock; uniform time fade with a scoped twilight band"

This reverts commit 0dac024cdb.
This commit is contained in:
Erik 2026-08-23 18:26:16 +02:00
parent 0dac024cdb
commit 9fcc3f4870
10 changed files with 15 additions and 98 deletions

View file

@ -333,18 +333,6 @@ internal sealed class FrameRootCompositionPhase
skyForNightSky.EnhancedNightSkyActive = () =>
nightSkyController.ActiveRuntime?.Descriptor.Id
== AcDream.App.Rendering.Packs.BuiltInAtmosphericRenderPack.Id;
// The starfield wheels with the Dereth clock: one turn per
// day about the celestial pole plus ~1 degree/night of
// seasonal drift (dayOfYear/360) — sky.frag's rotation block.
var nightSkyTime = d.WorldTime;
skyForNightSky.NightSkyRotationTurns = () =>
{
var cal = nightSkyTime.CurrentCalendar;
int dayOfYear = (int)cal.Month
* AcDream.Core.World.DerethDateTime.DaysInAMonth
+ (cal.Day - 1);
return (float)(nightSkyTime.DayFraction + dayOfYear / 360.0);
};
}
}

View file

@ -43,10 +43,6 @@ layout(std140, ACDREAM_UBO_SET binding = 4) uniform SkyParams {
vec2 uUvScroll;
float uApplyFog;
float uSurfOpacity;
float uNightSkyRotationTurns; // enhanced night sky (IA-26): sky rotation
float uNsPadA;
float uNsPadB;
float uNsPadC;
};
struct Light {
@ -190,50 +186,18 @@ vec3 nightSky(vec3 dir, uint seed)
void main() {
if (uParamA > 0.5) {
// Day/night fade from the UNIFORM ambient term only — the first
// gate's vTint signal carried the per-vertex sun-facing product and
// blanked stars across the whole twilight half of the sky
// (2026-08-23 screenshots). Ambient is one value for the sky, so
// star visibility is even everywhere; the twilight glow gets its
// own tightly-scoped suppression below.
float dayL = dot(uAmbientColor, vec3(0.299, 0.587, 0.114));
float night = 1.0 - smoothstep(0.10, 0.32, dayL);
// The star layer's own retail lighting product (Emissive 0 ->
// ambient + diffuse) is the day/night signal: ~0.1 at deep night,
// ~1.0 at noon. Stars at full strength only under a dark sky.
float dayL = dot(vTint, vec3(0.299, 0.587, 0.114));
float night = 1.0 - smoothstep(0.18, 0.45, dayL);
if (night < 0.004) {
// Daytime: the whole lattice would multiply to zero — skip it
// so the enhanced sky costs nothing outside dusk-to-dawn.
fragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
vec3 d = normalize(vDir);
// Subtle twilight suppression: only the low sky (bottom ~19 deg)
// toward the sun's azimuth, and only while the sun term is strong
// (dusk/dawn) — stars near the bright horizon wash out, the rest
// of the sky keeps its full carpet.
vec3 dflat = normalize(vec3(d.xy, 0.0) + vec3(1e-5, 0.0, 0.0));
vec3 sflat = normalize(vec3(uSunDir.xy, 0.0) + vec3(1e-5, 0.0, 0.0));
float glowSide = max(dot(dflat, sflat), 0.0);
float lowSky = 1.0 - clamp(d.z * 3.0, 0.0, 1.0);
float twilight = clamp(
dot(uSunColor, vec3(0.299, 0.587, 0.114)) * uDiffuseFactor,
0.0, 1.0);
night *= 1.0 - 0.85 * twilight * glowSide * glowSide * lowSky;
// The sky wheels: one revolution per Dereth day about a celestial
// pole ~41 deg above the northern horizon (+Y north, +Z up), plus
// ~1 deg/night of seasonal drift folded into the turns value
// (dayFraction + dayOfYear/360). Rodrigues rotation of the sample
// direction; stars and mottle turn together.
const vec3 NS_POLE = vec3(0.0, 0.6598, 0.7514);
float ang = 6.28318530718 * fract(uNightSkyRotationTurns);
float ca = cos(ang);
float sa = sin(ang);
vec3 rdir = d * ca
+ cross(NS_POLE, d) * sa
+ NS_POLE * dot(NS_POLE, d) * (1.0 - ca);
vec3 sky = nightSky(rdir, uint(uParamB));
vec3 sky = nightSky(normalize(vDir), uint(uParamB));
// Additive pipeline (forced for this draw): rgb adds over the dome.
fragColor = vec4(sky * night, 1.0);
return;

View file

@ -67,10 +67,6 @@ layout(std140, ACDREAM_UBO_SET binding = 4) uniform SkyParams {
vec2 uUvScroll;
float uApplyFog; // 1 for foggable layers; raw-additive keeps fog off
float uSurfOpacity; // final surface opacity multiplier from the CPU
float uNightSkyRotationTurns; // enhanced night sky (IA-26): sky rotation
float uNsPadA;
float uNsPadB;
float uNsPadC;
};
// Shared SceneLighting UBO — we need uFogParams.xy (fog start/end) to

View file

@ -311,12 +311,12 @@
"stages": [
{
"stage": "vert",
"sourceSha256": "80c190d5544433bd6b08810c1e5040cec5090fe91839f436728d5454ed7f3c31",
"sourceSha256": "9102b156bd4fd667831353640b2feee2ddde66e88579a4e425566c9b67304b64",
"compiled": true
},
{
"stage": "frag",
"sourceSha256": "76481dcc1a321c65308bf9c081254978ee7f12413166df5d32a1606228bdc768",
"sourceSha256": "e7ccdb4d5fece2ceeb48eb43aaa827424df2b68614987eeb3dfb7880dff8ea83",
"compiled": true
}
]

View file

@ -106,13 +106,6 @@ public sealed partial class SkyRenderer : IDisposable
/// </summary>
internal Func<bool>? EnhancedNightSkyActive { get; set; }
/// <summary>
/// Dereth-clock rotation source for the enhanced night sky, in turns
/// (dayFraction + dayOfYear/360). Composition wires it to the world
/// time service; evaluated once per sky pass.
/// </summary>
internal Func<float>? NightSkyRotationTurns { get; set; }
/// <summary>Deterministic seed for the procedural sky's hash grids —
/// the approved-look generator's seed (gen_starfield2.py, 2026-08-23).</summary>
private const float NightSkySeed = 11f;
@ -216,8 +209,6 @@ public sealed partial class SkyRenderer : IDisposable
// that FOV here, including the near-180-degree teleport transition.
var skyProj = SkyProjection.WithDepthRange(camera.Projection, Near, Far);
_params.NightSkyRotationTurns = NightSkyRotationTurns?.Invoke() ?? 0f;
// View with translation zeroed — keeps the sky at camera origin
// regardless of camera position in the world.
var skyView = camera.View;
@ -735,20 +726,9 @@ public sealed partial class SkyRenderer : IDisposable
public Vector2 UvScroll; // 240
public float ApplyFog; // 248
public float SurfOpacity; // 252
/// <summary>
/// Whole-sky rotation in TURNS for the enhanced night sky (IA-26):
/// dayFraction + dayOfYear/360, so the procedural starfield wheels
/// once per Dereth day about the celestial pole and drifts ~1 degree
/// per night through the 360-day year (seasonal constellations).
/// Zero when the pack is inactive; the retail path never reads it.
/// </summary>
public float NightSkyRotationTurns; // 256
public float NsPadA; // 260
public float NsPadB; // 264
public float NsPadC; // 268
/// <summary>272 — the std140 size of the block, a whole number of vec4s.</summary>
public const int SizeInBytes = 272;
/// <summary>256 — the std140 size of the block, a whole number of vec4s.</summary>
public const int SizeInBytes = 256;
}
private sealed class SubMeshGpu

View file

@ -52,8 +52,8 @@ public sealed class VulkanShaderManifestTests
// override, retail's GameSky::Draw @0x00506FF0 rule (see
// SkyFogRuleTests). A deliberate default-path change, reviewed
// with the world-fog-range fix in the same commit.
["sky.frag.spv"] = "83a7b4e265f7df4726d716a812ebaa74ba31ea47036bc31005cd8dc1d8981967",
["sky.vert.spv"] = "988eff4e106422ca483d665ba25818e8394737a247e9bae346db3220ac31fd28",
["sky.frag.spv"] = "e307a7f3cf84aada86db7c2859c55841a650b46732f12149986562cef0a90ca8",
["sky.vert.spv"] = "3b51945fa4ff1be1604144df92866bdd47aade22f9dd90267591ef36adb28cde",
["terrain_modern.frag.spv"] = "7b3cdb01b837ed77ee20559a81c1ce5c9d5395300efcc072560ab0be3c5a1af9",
["terrain_modern.vert.spv"] = "9f4cb221ea6aed94a8d23af6cb8e3f3ed96c3cce6e50d135a72d3b55667b1557",
["ui_text.frag.spv"] = "37a281bf80441cb425eaa3ad8e0b3a43cfa21b74b60973ed4201718b9dc102df",

View file

@ -21,12 +21,7 @@ public sealed class EnhancedNightSkyRuleTests
string code = StripLineComments(frag);
Assert.Contains("if (uParamA > 0.5)", code, StringComparison.Ordinal);
Assert.Contains("nightSky(rdir, uint(uParamB))", code, StringComparison.Ordinal);
// The fade must stay UNIFORM across the sky (the first gate's
// per-vertex vTint signal blanked the whole twilight half) and the
// starfield must wheel with the Dereth clock.
Assert.Contains("dot(uAmbientColor, vec3(0.299, 0.587, 0.114))", code, StringComparison.Ordinal);
Assert.Contains("fract(uNightSkyRotationTurns)", code, StringComparison.Ordinal);
Assert.Contains("nightSky(normalize(vDir), uint(uParamB))", code, StringComparison.Ordinal);
// Screen-pixel star sizing is the reason this exists — the stretched
// texture flaw must not creep back in via a fixed-size grid, and the
// cube-face fwidth seams must not return (the 2026-08-23 gate's

View file

@ -8,7 +8,7 @@ namespace AcDream.App.Tests.Rendering;
/// <summary>
/// Campaign V slice V6e: the sky's dozen loose uniforms became one std140
/// uniform block, and this is the test that keeps the CPU struct and the GLSL
/// block describing the same 272 bytes.
/// block describing the same 256 bytes.
///
/// <para>It exists because the failure mode is silent. std140 gives a
/// <c>vec3</c> 16-byte alignment while only using 12, so the block deliberately
@ -45,12 +45,6 @@ public sealed class SkyParamsLayoutTests
[InlineData("UvScroll", 240)]
[InlineData("ApplyFog", 248)]
[InlineData("SurfOpacity", 252)]
// IA-26: the enhanced night sky's rotation turns plus its three pad
// words, filling the seventeenth vec4 exactly.
[InlineData("NightSkyRotationTurns", 256)]
[InlineData("NsPadA", 260)]
[InlineData("NsPadB", 264)]
[InlineData("NsPadC", 268)]
public void EveryMemberSitsWhereStd140PutsIt(string member, int expectedOffset)
{
Assert.Equal(
@ -66,7 +60,7 @@ public sealed class SkyParamsLayoutTests
?.GetRawConstantValue()
?? throw new InvalidOperationException("SkyParams.SizeInBytes is missing."));
Assert.Equal(272, declared);
Assert.Equal(256, declared);
Assert.Equal(declared, Marshal.SizeOf(SkyParamsType));
// std140 rounds a block up to its largest member's alignment (16).
Assert.Equal(0, declared % 16);