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 shader outlineBuffer; 20uniform float2 uvOffsetFgd; 21uniform float2 uvScaleFgd; 22uniform float2 uvOffsetBgd; 23uniform float2 uvScaleBgd; 24uniform float time; 25uniform float screenAspectRatio; 26uniform float2 screenSize; 27uniform half intensity; 28 29#include "shaders/constants.agsl" 30#include "shaders/utils.agsl" 31#include "shaders/rain_shower.agsl" 32#include "shaders/rain_constants.agsl" 33#include "shaders/rain_splash.agsl" 34 35// Controls how visible the rain drops are. 36const float rainVisibility = 0.4; 37 38/** 39 * Draws splashes around the outline of the given image. 40 */ 41vec3 drawSplashes(vec2 uv, vec2 fragCoord, vec3 color) { 42 /** 1. Make a grid */ 43 vec2 gridSize = vec2(15., 15.); 44 // Aspect ratio impacts visible cells. 45 gridSize.y /= screenAspectRatio; 46 // Scale the UV to allocate number of rows and columns. 47 vec2 gridUv = uv * gridSize; 48 // Invert y (otherwise it goes from 0=top to 1=bottom). 49 gridUv.y = 1. - gridUv.y; 50 // Generate column id, to offset columns vertically (so rain is not aligned). 51 float columnOffset = idGenerator(floor(gridUv.x)); 52 gridUv.y += columnOffset * 2.6; 53 54 // For each cell, we set the internal UV from -0.5 (left, bottom) to 0.5 (right, top). 55 vec2 cellUv = fract(gridUv) - 0.5; 56 vec2 pixUv = cellUv; 57 pixUv.x *= -1; 58 vec2 pixDistance = screenSize * pixUv / gridSize; 59 float2 uvTextureFgd = (fragCoord + pixDistance) * uvScaleFgd + uvOffsetFgd; 60 61 float outline = step(0.1, outlineBuffer.eval(uvTextureFgd).r); 62 if (outline < 0.1) { 63 // Simply return the given color when it's not considered as an outline. 64 return color; 65 } 66 67 float t = time + 53.512 * columnOffset; 68 float delay = 1.5173; 69 float duration = 1.2; 70 71 float circletime = floor(t / (duration + delay)); 72 // Get the cell ID based on the grid position. [0, 1]. 73 float cellId = idGenerator(floor(gridUv) + vec2(circletime, 23.14)); 74 // Normalized time [0, 1]. 75 float cellTime = max((mod(t + delay * cellId, duration + delay) - delay) / duration, 0.); 76 77 float splash = drawSplash(cellUv, cellTime) * smoothstep(0., 0.45, intensity); 78 79 return normalBlendWithWhiteSrc(color, splash); 80} 81 82vec4 main(float2 fragCoord) { 83 float2 uv = fragCoord / screenSize; 84 85 // Adjusts the UVs to have the expected rect of the image. 86 float2 uvTextureFgd = fragCoord * uvScaleFgd + uvOffsetFgd; 87 float2 uvTextureBgd = fragCoord * uvScaleBgd + uvOffsetBgd; 88 89 vec4 colorForeground = foreground.eval(uvTextureFgd); 90 vec4 color = background.eval(uvTextureBgd); 91 92 // Add rotation for the rain (as a default sin(time * 0.05) can be used). 93 float variation = wiggle(time - uv.y * 1.1, 0.10); 94 uv = rotateAroundPoint(uv, vec2(0.5, -1.42), variation * PI / 9.); 95 96 // 1. Generate a layer of rain behind the subject. 97 Rain rain = generateRain( 98 uv, 99 screenAspectRatio, 100 time * 18., 101 /* Grid size = */ vec2(20.0, 2.0), 102 intensity); 103 104 color.rgb = mix(color.rgb, highlightColor, rainVisibility * rain.dropMask); 105 106 // 2. Generate mid layer of rain behind the subject. 107 rain = generateRain( 108 uv, 109 screenAspectRatio, 110 time * 21.4, 111 /* Grid size = */ vec2(30.0, 4.0), 112 intensity); 113 114 // 3. Blend those layers. 115 color.rgb = mix(color.rgb, highlightColor, rainVisibility * rain.dropMask); 116 117 // 4. Blend with the foreground. Any effect from here will be in front of the subject. 118 color.rgb = normalBlend(color.rgb, colorForeground.rgb, colorForeground.a); 119 120 // 5. Draw splashes 121 color.rgb = drawSplashes(uv, fragCoord, color.rgb); 122 123 // 6. Generate a layer of rain in front of the subject (bigger and faster). 124 rain = generateRain( 125 uv, 126 screenAspectRatio, 127 time * 27., 128 /* Grid size = */ vec2(8.0, 3.0), 129 intensity); 130 131 // Closer rain drops are less visible. 132 color.rgb = mix(color.rgb, highlightColor, 0.7 * rainVisibility * rain.dropMask); 133 134 return color; 135} 136