• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2023 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 shader fog;
20uniform shader clouds;
21uniform half2 fogSize;
22uniform half2 cloudsSize;
23uniform half4 time;
24uniform half screenAspectRatio;
25uniform half2 screenSize;
26uniform half pixelDensity;
27uniform half intensity;
28uniform mat3 transformMatrixBitmap;
29uniform mat3 transformMatrixWeather;
30
31#include "shaders/constants.agsl"
32#include "shaders/utils.agsl"
33#include "shaders/simplex2d.agsl"
34
35const vec3 fogScrimColor = vec3(0.20);
36const vec3 fogColor = vec3(1.0);
37
38vec4 main(float2 fragCoord) {
39    vec2 timeForeground = vec2(time.x, time.y);
40    vec2 timeBackground = vec2(time.z, time.w);
41
42    /**
43     * The shader is composed by two image textures (foreground and background) and four layers of
44     * fog. The rendering order (back to front) is the following:
45     * - Background
46     * - bgdFogFar (layer 1) / bgdFogClose (layer 2)
47     * - Foreground
48     * - fgdFogFar (layer 1) / fgdFogClose (layer 2)
49     */
50    float2 adjustedCoord = transformPoint(transformMatrixBitmap, fragCoord);
51    float2 uv = transformPoint(transformMatrixWeather, fragCoord) / screenSize;
52    uv.y /= screenAspectRatio;
53
54    // Load background and foreground.
55    vec4 fgd = foreground.eval(adjustedCoord);
56    vec4 bgd = background.eval(adjustedCoord);
57
58    // Adjusts contrast and brightness.
59    float noise = 0.025 * triangleNoise(fragCoord.xy + vec2(12.31, 1024.1241));
60    bgd.rgb = imageRangeConversion(bgd.rgb, 0.8, 0.02, noise, intensity);
61    fgd.rgb = imageRangeConversion(fgd.rgb, 0.8, 0.02, noise, intensity);
62
63    // Blend them with constant solid fog color.
64    bgd.rgb = mix(bgd.rgb, fogScrimColor, 0.14 * intensity * bgd.a);
65    fgd.rgb = mix(fgd.rgb, fogScrimColor, 0.12 * intensity * fgd.a);
66    /* Add first layer: background. */
67    // set background color as the starting layer.
68    vec4 color = bgd;
69
70    /* Prepare fog layers. */
71    // Dither to be applied to background noise.
72    float bgdDither = triangleNoise((fragCoord + 0.0002 * timeBackground) * pixelDensity) * 0.075;
73
74    // The furthest fog layer in the background.
75    vec4 bgdFogFar = fog.eval(
76        fogSize * uv +
77        // Moves UV based on time.
78        vec2(timeBackground * 1.5) +
79        // Adds sampling dithering.
80        vec2(bgdDither * 14));
81
82    // The furthest fog layer in the background.
83    vec4 bgdFogClose = fog.eval(
84        0.5 * fogSize * uv +
85        // Moves UV based on time.
86        vec2(timeBackground * 5.5) +
87        // Adds sampling dithering.
88        vec2(bgdDither * 40));
89
90    float fgdDither = triangleNoise((fragCoord + 0.003 * timeForeground) * pixelDensity) * 0.09;
91    vec4 fgdFogFar = clouds.eval(
92        0.5 * cloudsSize * uv +
93        // Moves UV based on time.
94        vec2(timeForeground * 15.) +
95        // Adds distosions based on noise.
96        vec2(bgdFogFar.b * 20., bgdFogFar.g * 2) +
97        // Adds sampling dithering.
98        vec2(fgdDither * 12));
99    vec4 fgdFogClose = clouds.eval(
100        0.5 * cloudsSize * uv +
101        // moves UV based on time.
102        vec2(timeForeground * 32.) +
103        // Adds distosions based on noise.
104        vec2(bgdFogFar.g * 2., bgdFogFar.b * 10) +
105        // Adds sampling dithering.
106        vec2(fgdDither * 22));
107
108    // Undo aspect ratio adjustment.
109    uv.y *= screenAspectRatio;
110
111    /* Add second layer: background fog (far or 1, and close or 2). */
112    // background, layer 1.
113    float fogHeightVariation;
114    if (uv.y < 0.38) {
115        fogHeightVariation = 0.03 * cos(uv.x * 2.5 + timeBackground.x * 0.07);
116        float bgFogFarCombined = map(bgdFogFar.r, 0.74, 0.9, fgdFogFar.g, 0.95) * bgdFogFar.r;
117        float bgdFogLayer1 =
118            bgFogFarCombined *
119            smoothstep(-0.1, 0.05, uv.y + fogHeightVariation) *
120            (1. - smoothstep(0.15, 0.35, uv.y + fogHeightVariation));
121        bgdFogLayer1 *= 1.1;
122        bgdFogLayer1 += 0.55 * bgdDither;
123        bgdFogLayer1 = clamp(bgdFogLayer1, 0., 1.);
124        // Blend with background.
125        color.rgb =
126            normalBlendNotPremultiplied(color.rgb, fogColor * 0.8, bgdFogLayer1 * intensity);
127    }
128
129    if (uv.y > 0.23 && uv.y < 0.87) {
130        // background, layer 2.
131        float fbmSimplexWorley = bgdFogClose.g * 0.625 + bgdFogClose.b * 0.3755;
132        float bgFogloseCombined = smoothstep(0.88 * fbmSimplexWorley, 1., bgdFogClose.r);
133        fogHeightVariation = 0.02 * sin(uv.x * 2.5 + timeBackground.x * 0.09);
134        float bgdFogLayer2 =
135            bgFogloseCombined *
136            smoothstep(0.25, 0.55, uv.y + fogHeightVariation) *
137            (1. - smoothstep(0.7, 0.85, uv.y + fogHeightVariation));
138        bgdFogLayer2 *= 1.2;
139        bgdFogLayer2 += 0.6 * bgdDither;
140        bgdFogLayer2 = clamp(bgdFogLayer2, 0., 1.);
141        // Blend with background.
142        color.rgb =
143            normalBlendNotPremultiplied(color.rgb, fogColor * 0.85, bgdFogLayer2 * intensity);
144    }
145
146    /* Add third layer: foreground. */
147    // Add the foreground. Any effect from here will be in front of the subject.
148    color.rgb = normalBlend(color.rgb, fgd.rgb, fgd.a);
149
150    /* Add fourth layer: foreground fog (far or 1, and close or 2). */
151    // foreground fog, layer 1.
152    if (uv.y > 0.32) {
153        fogHeightVariation = 0.1 * cos(uv.x * 2.5 + timeForeground.x * 0.085);
154        float fgdFogLayer1 =
155                mix(
156                    fgdFogFar.r,
157                    1.,
158                    0.5 * intensity * smoothstep(0.72, 0.92, uv.y + fogHeightVariation)) *
159                smoothstep(0.42, 0.82, uv.y + fogHeightVariation);
160        fgdFogLayer1 *= 1.3;
161        fgdFogLayer1 += 0.6 * fgdDither;
162        fgdFogLayer1 = clamp(fgdFogLayer1, 0., 1.);
163        color.rgb =
164            normalBlendNotPremultiplied(color.rgb, fogColor * 0.9, fgdFogLayer1 * intensity);
165    }
166    if (uv.y > 0.25) {
167        // Foreground fog, layer 2.
168        fogHeightVariation = 0.05 * sin(uv.x * 2. + timeForeground.y * 0.5);
169        float fgdFogLayer2 =
170                mix(
171                    fgdFogClose.g,
172                    1.,
173                    0.65 * intensity * smoothstep(0.85, 1.3, uv.y + fogHeightVariation)) *
174                smoothstep(0.30, 0.90, uv.y + uv.x * 0.09);
175        fgdFogLayer2 *= 1.4;
176        fgdFogLayer2 += 0.6 * fgdDither;
177        fgdFogLayer2 = clamp(fgdFogLayer2, 0., 1.);
178        color.rgb = normalBlendNotPremultiplied(color.rgb, fogColor, fgdFogLayer2 * intensity);
179    }
180    return color;
181}