1/*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17uniform shader foreground;
18uniform shader background;
19uniform float screenAspectRatio;
20uniform float2 screenSize;
21uniform float time;
22uniform float intensity;
23uniform mat3 transformMatrixBitmap;
24uniform mat3 transformMatrixWeather;
25
26
27#include "shaders/constants.agsl"
28#include "shaders/utils.agsl"
29#include "shaders/simplex3d.agsl"
30
31#include "shaders/lens_flare.agsl"
32
33const vec2 sunCenter = vec2(0.57, -0.8);
34const vec3 godRaysColor = vec3(1., 0.857, 0.71428);
35
36float calculateRay(float angle, float time) {
37    /*
38     * God rays oscilations. It works like a fourier series, using the the uv position angle
39     * and time and phase to adjust how it looks.
40     */
41    float rays = 17.5 + 8.0 * sin(3. * angle + time);
42    rays += 4.0 * sin(12. * angle - 0.3 * time);
43    rays += 4.0 * sin(25. * angle + 0.9252 * time);
44    rays += -1.8 * cos(38. * angle - 0.114 * time);
45    rays += 0.45 * cos(60.124 * angle + 0.251 * time);
46    return rays;
47}
48
49float godRays(vec2 uv, vec2 center, float phase, float frequency, float time, float intensity) {
50    // Adjust position to center.
51    uv -= center;
52    // For each position, get the angle.
53    float angle = atan(uv.y, uv.x);
54    // The glow around the position of the sun.
55    float sunGlow = 1.0 / (1. + 20.0 * length(uv));
56    float rays = calculateRay(angle * frequency, phase + time);
57    return intensity * sunGlow * (rays * 0.4 + 2 + 2 * length(uv));
58}
59
60vec3 addGodRays(
61    vec3 background,
62    vec2 fragCoord,
63    vec2 uv,
64    vec2 sunPos,
65    float phase,
66    float frequency,
67    float timeSpeed) {
68    float rays =
69        godRays(
70            uv,
71            sunPos,
72            phase,
73            frequency,
74            timeSpeed * time,
75            intensity);
76    // Dithering.
77    rays -= triangleNoise(fragCoord.xy) * 0.025;
78    rays = clamp(rays, 0., 1.);
79    vec3 raysColor = mix(godRaysColor, min(godRaysColor + 0.5, vec3(1)), smoothstep(0.15, 0.6, rays));
80    return normalBlendNotPremultiplied(background.rgb, raysColor, smoothstep(0.1, 1., rays));
81}
82
83float checkBrightnessGodRaysAtCenter(
84    vec2 center,
85    float phase,
86    float frequency,
87    float timeSpeed) {
88    // For each position, get the angle.
89    float angle = atan(-center.y, -center.x);
90    float rays = calculateRay(angle * frequency, phase + timeSpeed * time);
91    // Normalize [0, 1] the brightness.
92    return smoothstep(-0.75, 35.25, rays);
93
94}
95
96vec4 main(float2 fragCoord) {
97    // Apply transform matrix to fragCoord
98    float2 adjustedUv = transformPoint(transformMatrixBitmap, fragCoord);
99
100    float2 uv = transformPoint(transformMatrixWeather, fragCoord) / screenSize;
101    uv -= vec2(0.5, 0.5);
102    uv.y /= screenAspectRatio;
103    vec2 sunVariation = vec2(0.1 * sin(time * 0.3), 0.14 * cos(time * 0.5));
104    sunVariation += 0.1 * (0.5 * sin(time * 0.456) + 0.5) * sunCenter / vec2(1., screenAspectRatio);
105    vec2 sunPos = sunVariation + sunCenter / vec2(1., screenAspectRatio);
106    //TODO(b/375214506): fix the uv position of the sun
107
108    vec4 colorForeground = foreground.eval(adjustedUv);
109    vec4 color = background.eval(adjustedUv);
110    // add foreground
111    color.rgb = normalBlend(color.rgb, colorForeground.rgb, colorForeground.a);
112
113    // Calculate brightness from sunrays.
114    float brightnessSunray = checkBrightnessGodRaysAtCenter(sunPos, 10.0, 1.1, 0.9);
115    brightnessSunray *= brightnessSunray;
116
117    // Adjusts contrast and brightness.
118    float noise = 0.025 * triangleNoise(fragCoord.xy + vec2(12.31, 1024.1241));
119    color.rgb = imageRangeConversion(color.rgb, 0.88, 0.02, noise, intensity);
120
121    // Adjust color grading for shadows and highlights.
122    float lum = relativeLuminance(color.rgb);
123    vec3 highlightColor = vec3(0.41, 0.69, 0.856);
124    float highlightThres = 0.66;
125    float highlightBlend = 0.30 +  + brightnessSunray * 0.1;
126    vec3 shadowColor = vec3(0.756, 0.69, 0.31);
127    float shadowThres = 0.33;
128    float shadowBlend = 0.2 + brightnessSunray * 0.1;
129
130    float highlightsMask = smoothstep(highlightThres, 1., lum);
131    float shadowsMask = 1. - smoothstep(0., shadowThres, lum);
132
133    color.rgb = normalBlendNotPremultiplied(
134        color.rgb, shadowColor, intensity * shadowBlend * shadowsMask);
135    color.rgb = normalBlendNotPremultiplied(
136        color.rgb, highlightColor, intensity * highlightBlend * highlightsMask);
137
138    // Add god rays.
139    color.rgb = addGodRays(color.rgb, fragCoord.xy, uv, sunPos, 10.0, 1.1, 0.9);
140    // Add flare.
141    color.rgb = addFlare(color.rgb, uv, sunPos, (0.4 + 0.8 * brightnessSunray) * intensity, time);
142    return color;
143}
144