summaryrefslogtreecommitdiff
path: root/weathereffects/assets/shaders/glass_rain.agsl
blob: 9e0b9c58156ec4a0e9730cbeb0c83a649e7a2eeb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

struct GlassRain {
    highp vec2 drop;
    highp float dropMask;
    highp vec2 dropplets;
    highp float droppletsMask;
    highp float trailMask;
    highp vec2 cellUv;
};

/**
 * Generates information to show some rain running down a foggy glass surface.
 *
 * @param uv the UV of the fragment where we will display the rain effect.
 * @param screenAspectRatio the aspect ratio of the fragment where we will display the effect.
 * @param time the elapsed time.
 * @param rainGridSize the size of the grid, where each cell contains a main drop and some
 * dropplets.
 * @param rainIntensity how many of the cells will contain drops. Value from 0 (no rain) to 1
 * (each cell contains a drop).
 *
 * @returns GlassRain an object containing all the info to draw the rain.
 */
GlassRain generateGlassRain(
    // UVs of the target fragment (normalized).
    in vec2 uv,
    in float screenAspectRatio,
    in float time,
    in vec2 rainGridSize,
    in float rainIntensity
) {
    vec2 dropPos = vec2(0.);
    float cellMainDropMask = 0.0;
    vec2 trailDropsPos = vec2(0.);
    float cellDroppletsMask = 0.0;
    float cellTrailMask = 0.0;

    /* Grid. */
    // Number of rows and columns (each one is a cell, a drop).
    float cellAspectRatio = rainGridSize.x / rainGridSize.y;
    // Aspect ratio impacts visible cells.
    rainGridSize.y /= screenAspectRatio;
    // scale the UV to allocate number of rows and columns.
    vec2 gridUv = uv * rainGridSize;
    // Invert y (otherwise it goes from 0=top to 1=bottom).
    gridUv.y = 1. - gridUv.y;
    float verticalGridPos = 2.4 * time / 5.0;
    // Move grid vertically down.
    gridUv.y += verticalGridPos;

    /* Cell. */
    // Get the cell ID based on the grid position. Value from 0 to 1.
    float cellId = idGenerator(floor(gridUv));
    // For each cell, we set the internal UV from -0.5 (left, bottom) to 0.5 (right, top).
    vec2 cellUv = fract(gridUv) - 0.5;

    /* Cell-id-based variations. */
    // Adjust time based on cellId.
    time += cellId * 7.1203;
    // Adjusts UV.y based on cell ID. This will make that the wiggle variation is different for
    // each cell.
    uv.y += cellId * 3.83027;
    // Adjusts scale of each drop (higher is smaller).
    float scaleVariation = 1.0 + 0.7 * cellId;
    // Make some cells to not have drops.
    if (cellId < 1. - rainIntensity) {
        return GlassRain(dropPos, cellMainDropMask, trailDropsPos, cellDroppletsMask,
            cellTrailMask, cellUv);
    }

    /* Cell main drop. */
    // vertical movement: Fourier Series-Sawtooth Wave (ascending: /|/|/|).
    float verticalSpeed = TAU / 5.0;
    float verticalPosVariation = 0.45 * 0.63 * (
            -1.2 * sin(verticalSpeed * time)
            -0.5 * sin(2. * verticalSpeed * time)
            -0.3333 * sin(3. * verticalSpeed * time)
    );

    // Horizontal movement: Wiggle.
    float wiggleSpeed = 6.0;
    float wiggleAmp = 0.5;
    // Define the start based on the cell id.
    float horizontalStartAmp = 0.5;
    float horizontalStart = (cellId - 0.5) * 2.0 * horizontalStartAmp / cellAspectRatio;
    // Add the wiggle (equation decided by testing in Grapher).
    float horizontalWiggle = wiggle(uv.y, wiggleSpeed);

    // Add the start and wiggle and make that when we are closer to the edge, we don't wiggle much
    // (so the drop doesn't go outside it's cell).
    horizontalWiggle = horizontalStart
        + (horizontalStartAmp - abs(horizontalStart)) * wiggleAmp * horizontalWiggle;

    // Calculate main cell drop.
    float dropPosUncorrected = (cellUv.x - horizontalWiggle);
    dropPos.x = dropPosUncorrected / cellAspectRatio;
    // Create tear drop shape.
    verticalPosVariation -= dropPosUncorrected * dropPosUncorrected / cellAspectRatio;
    dropPos.y = cellUv.y - verticalPosVariation;
    // Adjust scale.
    dropPos *= scaleVariation;
    // Create a circle for the main drop in the cell, based on position.
    cellMainDropMask = smoothstep(0.06, 0.04, length(dropPos));

    /* Cell trail dropplets. */
    trailDropsPos.x = (cellUv.x - horizontalWiggle)/ cellAspectRatio;
    // Substract verticalGridPos to mage the dropplets stick in place.
    trailDropsPos.y = cellUv.y -verticalGridPos;
    trailDropsPos.y = (fract(trailDropsPos.y * 4.) - 0.5) / 4.;
    // Adjust scale.
    trailDropsPos *= scaleVariation;
    cellDroppletsMask = smoothstep(0.03, 0.02, length(trailDropsPos));
    // Fade the dropplets frop the top the farther they are from the main drop.
    // Multiply by 1.2 so we show more of the trail.
    float verticalFading = 1.2 * smoothstep(0.5, verticalPosVariation, cellUv.y);
    cellDroppletsMask *= verticalFading;
    // Mask dropplets that are under main cell drop.
    cellDroppletsMask *= smoothstep(-0.06, 0.08, dropPos.y);

    /* Cell trail mask (it will show the image unblurred). */
    // Gradient for top of the main drop.
    cellTrailMask = smoothstep(-0.04, 0.04, dropPos.y);
    // Fades out the closer we get to the top of the cell.
    cellTrailMask *= verticalFading;
    // Only show the main section of the trail.
    cellTrailMask *= smoothstep(0.07, 0.02, abs(dropPos.x));

    cellDroppletsMask *= cellTrailMask;

    return GlassRain(
        dropPos, cellMainDropMask, trailDropsPos, cellDroppletsMask, cellTrailMask, cellUv);
}