Skip to content

Commit b26cc87

Browse files
committed
use Oklab and smoothstep for time of day transitions
- Implement sRGB <-> Linear <-> Oklab conversion in timeofday frag shader. - Mix time of day colors in Oklab space for perceptually uniform gradients. - Use `smoothstep` for the time factor in timeofday, atmosphere, and particle shaders to provide non-linear easing during transitions. - Synchronize intensity and emissive boost calculations with the new transition curve.
1 parent 93d43e3 commit b26cc87

3 files changed

Lines changed: 78 additions & 26 deletions

File tree

src/resources/shaders/legacy/weather/atmosphere/frag.glsl

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,12 @@ void main()
6767
float uCloudsIntensity = mix(uIntensities[2], uTargets[2], weatherLerp);
6868
float uFogIntensity = mix(uIntensities[3], uTargets[3], weatherLerp);
6969

70-
float timeOfDayLerp = clamp((uCurrentTime - uTimeOfDayStartTime) / uTransitionDuration,
71-
0.0,
72-
1.0);
70+
float tTod = clamp((uCurrentTime - uTimeOfDayStartTime) / uTransitionDuration, 0.0, 1.0);
71+
float timeOfDayLerp = smoothstep(0.0, 1.0, tTod);
7372
float currentTimeOfDayIntensity = mix(uTimeOfDay.z, uTimeOfDay.w, timeOfDayLerp);
74-
vec4 timeOfDayStart = uNamedColors[int(uTimeOfDay.x)];
75-
vec4 timeOfDayTarget = uNamedColors[int(uTimeOfDay.y)];
76-
vec4 uTimeOfDayColor = mix(timeOfDayStart, timeOfDayTarget, timeOfDayLerp);
77-
uTimeOfDayColor.a *= currentTimeOfDayIntensity;
73+
float alphaStart = uNamedColors[int(uTimeOfDay.x)].a;
74+
float alphaTarget = uNamedColors[int(uTimeOfDay.y)].a;
75+
float uTimeOfDayAlpha = mix(alphaStart, alphaTarget, timeOfDayLerp) * currentTimeOfDayIntensity;
7876

7977
// Atmosphere overlay is now transparent by default (TimeOfDay is drawn separately)
8078
vec4 result = vec4(0.0);
@@ -86,7 +84,7 @@ void main()
8684
float density = 0.4 + uFogIntensity * 0.4;
8785
vec4 fog = vec4(0.8, 0.8, 0.85, uFogIntensity * n * localMask * density);
8886
// Emissive boost at night
89-
fog.rgb += uTimeOfDayColor.a * 0.15;
87+
fog.rgb += uTimeOfDayAlpha * 0.15;
9088

9189
// Blend fog over result
9290
float combinedAlpha = 1.0 - (1.0 - result.a) * (1.0 - fog.a);
@@ -106,7 +104,7 @@ void main()
106104
1.0 * storminess,
107105
uCloudsIntensity * puffy * localMask * 0.5);
108106
// Emissive boost at night
109-
clouds.rgb += uTimeOfDayColor.a * 0.1;
107+
clouds.rgb += uTimeOfDayAlpha * 0.1;
110108

111109
// Blend clouds over result
112110
float combinedAlpha = 1.0 - (1.0 - result.a) * (1.0 - clouds.a);

src/resources/shaders/legacy/weather/particle/frag.glsl

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,29 +40,27 @@ void main()
4040
float pIntensity = max(pRain, pSnow);
4141
float pType = pSnow / max(pIntensity, 0.001);
4242

43-
float timeOfDayLerp = clamp((uCurrentTime - uTimeOfDayStartTime) / uTransitionDuration,
44-
0.0,
45-
1.0);
43+
float tTod = clamp((uCurrentTime - uTimeOfDayStartTime) / uTransitionDuration, 0.0, 1.0);
44+
float timeOfDayLerp = smoothstep(0.0, 1.0, tTod);
4645
float currentTimeOfDayIntensity = mix(uTimeOfDay.z, uTimeOfDay.w, timeOfDayLerp);
47-
vec4 timeOfDayStart = uNamedColors[int(uTimeOfDay.x)];
48-
vec4 timeOfDayTarget = uNamedColors[int(uTimeOfDay.y)];
49-
vec4 uTimeOfDayColor = mix(timeOfDayStart, timeOfDayTarget, timeOfDayLerp);
50-
uTimeOfDayColor.a *= currentTimeOfDayIntensity;
46+
float alphaStart = uNamedColors[int(uTimeOfDay.x)].a;
47+
float alphaTarget = uNamedColors[int(uTimeOfDay.y)].a;
48+
float uTimeOfDayAlpha = mix(alphaStart, alphaTarget, timeOfDayLerp) * currentTimeOfDayIntensity;
5149

5250
float lifeFade = smoothstep(0.0, 0.15, vLife) * smoothstep(1.0, 0.85, vLife);
5351

5452
// Rain visuals
5553
float streak = 1.0 - smoothstep(0.0, 0.15, abs(vLocalCoord.x - 0.5));
5654
float rainAlpha = mix(0.4, 0.7, clamp(pIntensity, 0.0, 1.0));
5755
vec4 rainColor = vec4(0.6, 0.6, 1.0, pIntensity * streak * vLocalMask * rainAlpha * lifeFade);
58-
rainColor.rgb += uTimeOfDayColor.a * 0.2;
56+
rainColor.rgb += uTimeOfDayAlpha * 0.2;
5957

6058
// Snow visuals
6159
float dist = distance(vLocalCoord, vec2(0.5));
6260
float flake = 1.0 - smoothstep(0.1, 0.2, dist);
6361
float snowAlpha = mix(0.6, 0.9, clamp(pIntensity, 0.0, 1.0));
6462
vec4 snowColor = vec4(1.0, 1.0, 1.1, pIntensity * flake * vLocalMask * snowAlpha * lifeFade);
65-
snowColor.rgb += uTimeOfDayColor.a * 0.3;
63+
snowColor.rgb += uTimeOfDayAlpha * 0.3;
6664

6765
// Interpolate visuals based on pType
6866
vec4 pColor = mix(rainColor, snowColor, pType);

src/resources/shaders/legacy/weather/timeofday/frag.glsl

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,78 @@ layout(std140) uniform WeatherBlock
2323

2424
out vec4 vFragmentColor;
2525

26+
vec3 srgbToLinear(vec3 c)
27+
{
28+
vec3 low = c / 12.92;
29+
vec3 high = pow((c + 0.055) / 1.055, vec3(2.4));
30+
return mix(low, high, step(vec3(0.04045), c));
31+
}
32+
33+
vec3 linearToSrgb(vec3 c)
34+
{
35+
vec3 low = c * 12.92;
36+
vec3 high = 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055;
37+
return mix(low, high, step(vec3(0.0031308), c));
38+
}
39+
40+
vec3 linearToOklab(vec3 c)
41+
{
42+
float l = 0.4122214708 * c.r + 0.5363325363 * c.g + 0.0514459929 * c.b;
43+
float m = 0.2119034982 * c.r + 0.6806995451 * c.g + 0.1073969566 * c.b;
44+
float s = 0.0883024619 * c.r + 0.2817188376 * c.g + 0.6299787005 * c.b;
45+
46+
float l_ = pow(l, 1.0 / 3.0);
47+
float m_ = pow(m, 1.0 / 3.0);
48+
float s_ = pow(s, 1.0 / 3.0);
49+
50+
return vec3(0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720403 * s_,
51+
1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_,
52+
0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_);
53+
}
54+
55+
vec3 oklabToLinear(vec3 c)
56+
{
57+
float l_ = c.x + 0.3963377774 * c.y + 0.2158037573 * c.z;
58+
float m_ = c.x - 0.1055613458 * c.y - 0.0638541728 * c.z;
59+
float s_ = c.x - 0.0894841775 * c.y - 1.2914855480 * c.z;
60+
61+
float l = l_ * l_ * l_;
62+
float m = m_ * m_ * m_;
63+
float s = s_ * s_ * s_;
64+
65+
return vec3(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
66+
-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
67+
-0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s);
68+
}
69+
2670
void main()
2771
{
2872
float uCurrentTime = uTime.x;
2973
float uTimeOfDayStartTime = uConfig.y;
3074
float uTransitionDuration = uConfig.z;
3175

32-
vec4 timeOfDayStart = uNamedColors[int(uTimeOfDay.x)];
33-
vec4 timeOfDayTarget = uNamedColors[int(uTimeOfDay.y)];
76+
vec4 timeOfDayStartSrgb = uNamedColors[int(uTimeOfDay.x)];
77+
vec4 timeOfDayTargetSrgb = uNamedColors[int(uTimeOfDay.y)];
78+
79+
float t = clamp((uCurrentTime - uTimeOfDayStartTime) / uTransitionDuration, 0.0, 1.0);
80+
float timeOfDayLerp = smoothstep(0.0, 1.0, t);
81+
82+
// Convert start and target colors to Oklab
83+
vec3 startOklab = linearToOklab(srgbToLinear(timeOfDayStartSrgb.rgb));
84+
vec3 targetOklab = linearToOklab(srgbToLinear(timeOfDayTargetSrgb.rgb));
85+
86+
// Interpolate in Oklab space
87+
vec3 mixedOklab = mix(startOklab, targetOklab, timeOfDayLerp);
88+
89+
// Convert back to sRGB
90+
vec3 mixedSrgb = linearToSrgb(oklabToLinear(mixedOklab));
3491

35-
float timeOfDayLerp = clamp((uCurrentTime - uTimeOfDayStartTime) / uTransitionDuration,
36-
0.0,
37-
1.0);
92+
// Mix intensity with smoothstep as well
3893
float currentTimeOfDayIntensity = mix(uTimeOfDay.z, uTimeOfDay.w, timeOfDayLerp);
3994

40-
vec4 uTimeOfDayColor = mix(timeOfDayStart, timeOfDayTarget, timeOfDayLerp);
41-
uTimeOfDayColor.a *= currentTimeOfDayIntensity;
95+
// Final color with alpha
96+
float finalAlpha = mix(timeOfDayStartSrgb.a, timeOfDayTargetSrgb.a, timeOfDayLerp);
97+
finalAlpha *= currentTimeOfDayIntensity;
4298

43-
vFragmentColor = uTimeOfDayColor;
99+
vFragmentColor = vec4(mixedSrgb, finalAlpha);
44100
}

0 commit comments

Comments
 (0)