diff --git a/src/AcDream.App/Composition/FrameRootComposition.cs b/src/AcDream.App/Composition/FrameRootComposition.cs index 3dc8f5d7..bfb78468 100644 --- a/src/AcDream.App/Composition/FrameRootComposition.cs +++ b/src/AcDream.App/Composition/FrameRootComposition.cs @@ -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); - }; } } diff --git a/src/AcDream.App/Rendering/Shaders/sky.frag b/src/AcDream.App/Rendering/Shaders/sky.frag index e56e4cae..a511ef4b 100644 --- a/src/AcDream.App/Rendering/Shaders/sky.frag +++ b/src/AcDream.App/Rendering/Shaders/sky.frag @@ -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; diff --git a/src/AcDream.App/Rendering/Shaders/sky.vert b/src/AcDream.App/Rendering/Shaders/sky.vert index e21fcdee..28a94d1a 100644 --- a/src/AcDream.App/Rendering/Shaders/sky.vert +++ b/src/AcDream.App/Rendering/Shaders/sky.vert @@ -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 diff --git a/src/AcDream.App/Rendering/Shaders/spv/shaders.manifest.json b/src/AcDream.App/Rendering/Shaders/spv/shaders.manifest.json index b4eaf1b0..dd84a830 100644 --- a/src/AcDream.App/Rendering/Shaders/spv/shaders.manifest.json +++ b/src/AcDream.App/Rendering/Shaders/spv/shaders.manifest.json @@ -311,12 +311,12 @@ "stages": [ { "stage": "vert", - "sourceSha256": "80c190d5544433bd6b08810c1e5040cec5090fe91839f436728d5454ed7f3c31", + "sourceSha256": "9102b156bd4fd667831353640b2feee2ddde66e88579a4e425566c9b67304b64", "compiled": true }, { "stage": "frag", - "sourceSha256": "76481dcc1a321c65308bf9c081254978ee7f12413166df5d32a1606228bdc768", + "sourceSha256": "e7ccdb4d5fece2ceeb48eb43aaa827424df2b68614987eeb3dfb7880dff8ea83", "compiled": true } ] diff --git a/src/AcDream.App/Rendering/Shaders/spv/sky.frag.spv b/src/AcDream.App/Rendering/Shaders/spv/sky.frag.spv index 2914922e..f6fc7441 100644 Binary files a/src/AcDream.App/Rendering/Shaders/spv/sky.frag.spv and b/src/AcDream.App/Rendering/Shaders/spv/sky.frag.spv differ diff --git a/src/AcDream.App/Rendering/Shaders/spv/sky.vert.spv b/src/AcDream.App/Rendering/Shaders/spv/sky.vert.spv index 3cff9d37..e69c1a43 100644 Binary files a/src/AcDream.App/Rendering/Shaders/spv/sky.vert.spv and b/src/AcDream.App/Rendering/Shaders/spv/sky.vert.spv differ diff --git a/src/AcDream.App/Rendering/Sky/SkyRenderer.cs b/src/AcDream.App/Rendering/Sky/SkyRenderer.cs index 84975d70..aec455b6 100644 --- a/src/AcDream.App/Rendering/Sky/SkyRenderer.cs +++ b/src/AcDream.App/Rendering/Sky/SkyRenderer.cs @@ -106,13 +106,6 @@ public sealed partial class SkyRenderer : IDisposable /// internal Func? EnhancedNightSkyActive { get; set; } - /// - /// 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. - /// - internal Func? NightSkyRotationTurns { get; set; } - /// Deterministic seed for the procedural sky's hash grids — /// the approved-look generator's seed (gen_starfield2.py, 2026-08-23). 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 - /// - /// 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. - /// - public float NightSkyRotationTurns; // 256 - public float NsPadA; // 260 - public float NsPadB; // 264 - public float NsPadC; // 268 - /// 272 — the std140 size of the block, a whole number of vec4s. - public const int SizeInBytes = 272; + /// 256 — the std140 size of the block, a whole number of vec4s. + public const int SizeInBytes = 256; } private sealed class SubMeshGpu diff --git a/tests/AcDream.App.Tests/Rendering/Gpu/Vk/VulkanShaderManifestTests.cs b/tests/AcDream.App.Tests/Rendering/Gpu/Vk/VulkanShaderManifestTests.cs index b33558fc..6a54192b 100644 --- a/tests/AcDream.App.Tests/Rendering/Gpu/Vk/VulkanShaderManifestTests.cs +++ b/tests/AcDream.App.Tests/Rendering/Gpu/Vk/VulkanShaderManifestTests.cs @@ -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", diff --git a/tests/AcDream.App.Tests/Rendering/Sky/EnhancedNightSkyRuleTests.cs b/tests/AcDream.App.Tests/Rendering/Sky/EnhancedNightSkyRuleTests.cs index 9a4fac2b..48ad7a82 100644 --- a/tests/AcDream.App.Tests/Rendering/Sky/EnhancedNightSkyRuleTests.cs +++ b/tests/AcDream.App.Tests/Rendering/Sky/EnhancedNightSkyRuleTests.cs @@ -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 diff --git a/tests/AcDream.App.Tests/Rendering/SkyParamsLayoutTests.cs b/tests/AcDream.App.Tests/Rendering/SkyParamsLayoutTests.cs index c9127818..7a9a0a82 100644 --- a/tests/AcDream.App.Tests/Rendering/SkyParamsLayoutTests.cs +++ b/tests/AcDream.App.Tests/Rendering/SkyParamsLayoutTests.cs @@ -8,7 +8,7 @@ namespace AcDream.App.Tests.Rendering; /// /// 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. /// /// It exists because the failure mode is silent. std140 gives a /// vec3 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);