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 float2 uvOffsetFgd;
24uniform float2 uvScaleFgd;
25uniform float2 uvOffsetBgd;
26uniform float2 uvScaleBgd;
27uniform half4 time;
28uniform half screenAspectRatio;
29uniform half2 screenSize;
30uniform half pixelDensity;
31uniform half intensity;
32
33#include "shaders/constants.agsl"
34#include "shaders/utils.agsl"
35#include "shaders/simplex2d.agsl"
36
37const vec3 fogColor = vec3(1.);
38
39vec4 main(float2 fragCoord) {
40    float2 uv = fragCoord / screenSize;
41    uv.y /= screenAspectRatio;
42
43    vec2 timeForeground = vec2(time.x, time.y);
44    vec2 timeBackground = vec2(time.z, time.w);
45
46    /**
47     * The shader is composed by two image textures (foreground and background) and four layers of
48     * fog. The rendering order (back to front) is the following:
49     * - Background
50     * - bgdFogFar (layer 1) / bgdFogClose (layer 2)
51     * - Foreground
52     * - fgdFogFar (layer 1) / fgdFogClose (layer 2)
53     */
54
55    // Load foreground and blend it with constant solid fog color.
56    vec4 fgd = foreground.eval(fragCoord * uvScaleFgd + uvOffsetFgd);
57    fgd.rgb = mix(fgd.rgb, fogColor, 0.32 * intensity * fgd.a);
58
59    // Load background and blend it with constant solid fog color.
60    vec4 bgd = background.eval(fragCoord * uvScaleBgd + uvOffsetBgd);
61    bgd.rgb = mix(bgd.rgb, fogColor, 0.15 * intensity * bgd.a);
62
63    /* Add first layer: background. */
64    // set background color as the starting layer.
65    vec4 color = bgd;
66
67    /* Prepare fog layers. */
68    // Dither to be applied to background noise.
69    float bgdDither = triangleNoise((fragCoord + 0.0002 * timeBackground) * pixelDensity) * 0.1;
70
71    // The furthest fog layer in the background.
72    vec4 bgdFogFar = fog.eval(
73        fogSize * uv +
74        // Moves UV based on time.
75        vec2(timeBackground * 1.5) +
76        // Adds sampling dithering.
77        vec2(bgdDither * 7));
78
79    // The furthest fog layer in the background.
80    vec4 bgdFogClose = fog.eval(
81        0.5 * fogSize * uv +
82        // Moves UV based on time.
83        vec2(timeBackground * 5.5) +
84        // Adds sampling dithering.
85        vec2(bgdDither * 22));
86
87    float fgdDither = triangleNoise((fragCoord + 0.003 * timeForeground) * pixelDensity) * 0.07;
88    vec4 fgdFogFar = clouds.eval(
89        0.5 * cloudsSize * uv +
90        // Moves UV based on time.
91        vec2(timeForeground * 10.) +
92        // Adds distosions based on noise.
93        vec2(bgdFogFar.b * 70., bgdFogFar.g * 10) +
94        // Adds sampling dithering.
95        vec2(fgdDither * 10));
96    vec4 fgdFogClose = clouds.eval(
97        0.5 * cloudsSize * uv +
98        // moves UV based on time.
99        vec2(timeForeground * 72.) +
100        // Adds distosions based on noise.
101        vec2(bgdFogFar.g * 50., bgdFogFar.b * 80) +
102        // Adds sampling dithering.
103        vec2(fgdDither * 8));
104
105    /* Add second layer: background fog (far or 1, and close or 2). */
106    // background, layer 1.
107    float bgdFogLayer1 =
108        map(bgdFogFar.r, 0.2, 1., fgdFogFar.g, 0.8) *
109        bgdFogFar.r *
110        (1. - 0.7 * bgdDither);
111    // Blend with background.
112    color.rgb = normalBlendWithWhiteSrc(color.rgb, bgdFogLayer1 * intensity);
113
114    // background, layer 2.
115    float fbmSimplexWorley = bgdFogClose.g * 0.625 + bgdFogClose.b * 0.3755;
116    float bgdFogLayer2 =
117        0.85 *
118        smoothstep(0.88 * fbmSimplexWorley, 1., bgdFogClose.r) *
119        (1.- 0.4 * bgdDither);
120    // Blend with background.
121    color.rgb = normalBlendWithWhiteSrc(color.rgb, bgdFogLayer2 * intensity);
122
123    /* Add third layer: foreground. */
124    // Add the foreground. Any effect from here will be in front of the subject.
125    color.rgb = normalBlend(color.rgb, fgd.rgb, fgd.a);
126
127    /* Add fourth layer: foreground fog (far or 1, and close or 2). */
128    // foreground fog, layer 1.
129    float fgdFogLayer1 =
130        fgdFogFar.r *
131        0.5 * (1. - fgdDither);
132    color.rgb = normalBlendWithWhiteSrc(color.rgb, fgdFogLayer1 * intensity);
133
134    // Foreground fog, layer 2.
135    float fgdFogLayer2 =
136            fgdFogClose.g *
137            0.4 * (1. - fgdDither);
138    color.rgb = normalBlendWithWhiteSrc(color.rgb, fgdFogLayer2 * intensity);
139
140    return color;
141}