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
17struct Rain {
18    highp float dropMask;
19    highp vec2 cellUv;
20};
21
22/**
23 * Pouring rain.
24 *
25 * @param uv the UV of the fragment where we will display the rain effect.
26 * @param screenAspectRatio the aspect ratio of the fragment where we will display the effect.
27 * @param time the elapsed time.
28 * @param rainGridSize the size of the grid, where each cell contains a main drop and some
29 * dropplets.
30 * @param rainIntensity how many of the cells will contain drops. Value from 0 (no rain) to 1
31 * (each cell contains a drop).
32 *
33 * @returns float with the rain info.
34 */
35Rain generateRain(
36    // UVs of the target fragment (normalized).
37    in vec2 uv,
38    in float screenAspectRatio,
39    in float time,
40    in vec2 rainGridSize,
41    in float rainIntensity
42) {
43    /* Grid. */
44    // Number of rows and columns (each one is a cell, a drop).
45    float cellAspectRatio = rainGridSize.x / rainGridSize.y;
46    // Aspect ratio impacts visible cells.
47    rainGridSize.y /= screenAspectRatio;
48    // scale the UV to allocate number of rows and columns.
49    vec2 gridUv = uv * rainGridSize;
50    // Invert y (otherwise it goes from 0=top to 1=bottom).
51    gridUv.y = 1. - gridUv.y;
52    float verticalGridPos = 0.4 * time;
53    // Move grid vertically down.
54    gridUv.y += verticalGridPos;
55    // Generate column id, to offset columns vertically (so rain is not aligned).
56    float columnId = idGenerator(floor(gridUv.x));
57    gridUv.y += columnId * 2.6;
58
59    /* Cell. */
60    // Get the cell ID based on the grid position. Value from 0 to 1.
61    float cellId = idGenerator(floor(gridUv));
62    // For each cell, we set the internal UV from -0.5 (left, bottom) to 0.5 (right, top).
63    vec2 cellUv = fract(gridUv) - 0.5;
64
65    float intensity = idGenerator(floor(vec2(cellId * 8.16, 27.2)));
66    if (intensity < 1. - rainIntensity) {
67        return Rain(0.0, cellUv);
68    }
69
70    /* Cell-id-based variations. */
71    // Adjust time based on columnId.
72    time += columnId * 7.1203;
73    // Adjusts scale of each drop (higher is smaller).
74    float scaleVariation = 1.0 - 0.3 * cellId;
75    float opacityVariation = (1. - 0.9 * cellId);
76
77    /* Cell drop. */
78    // Define the start based on the cell id.
79    float horizontalStart = 0.8 * (cellId - 0.5);
80
81    // Calculate drop.
82    vec2 dropPos = cellUv;
83        dropPos.y += -0.052;
84        dropPos.x += horizontalStart;
85        dropPos *= scaleVariation * vec2(14.2, 2.728);
86    // Create the drop.
87    float dropMask = smoothstep(
88        0.,
89        // Adjust the opacity.
90        .80 + 3. * cellId,
91        // Adjust the shape.
92        1. - length(vec2(dropPos.x, (dropPos.y - dropPos.x * dropPos.x)))
93    );
94
95    return Rain(dropMask, cellUv);
96}
97