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 float time; 21uniform float screenAspectRatio; 22uniform float gridScale; 23uniform float2 screenSize; 24uniform half intensity; 25uniform mat3 transformMatrixBitmap; 26uniform mat3 transformMatrixWeather; 27 28#include "shaders/constants.agsl" 29#include "shaders/utils.agsl" 30#include "shaders/rain_shower.agsl" 31#include "shaders/rain_constants.agsl" 32#include "shaders/rain_splash.agsl" 33#include "shaders/glass_rain.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.) * gridScale; 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 uvTexture = transformPoint(transformMatrixBitmap, fragCoord + pixDistance); 60 61 float outline = step(0.1, outlineBuffer.eval(uvTexture).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 screenBlend(color, splash); 80} 81 82vec4 main(float2 fragCoord) { 83 // 1. Generate rain shower. 84 // Apply transform matrix to fragCoord 85 float2 uvTexture = transformPoint(transformMatrixBitmap, fragCoord); 86 // Calculate uv for snow based on transformed coordinates 87 float2 uv = transformPoint(transformMatrixWeather, fragCoord) / screenSize; 88 89 vec4 colorForeground = foreground.eval(uvTexture); 90 vec4 color = background.eval(uvTexture); 91 92 // Adjusts contrast and brightness. 93 float noise = 0.025 * triangleNoise(fragCoord.xy + vec2(12.31, 1024.1241)); 94 color.rgb = imageRangeConversion(color.rgb, 0.84, 0.02, noise, intensity); 95 colorForeground.rgb = imageRangeConversion(colorForeground.rgb, 0.84, 0.02, noise, intensity); 96 97 // Add rotation for the rain (as a default sin(time * 0.05) can be used). 98 float variation = wiggle(time - uv.y * 1.1, 0.10); 99 vec2 uvRot = rotateAroundPoint(uv, vec2(0.5, -1.42), variation * PI / 9.); 100 101 // 1.1. Generate a layer of rain behind the subject. 102 Rain rain = generateRain( 103 uvRot, 104 screenAspectRatio, 105 time * 18., 106 /* Grid size = */ vec2(20.0, 2.0) * gridScale, 107 intensity); 108 109 color.rgb = mix(color.rgb, highlightColor, rainVisibility * rain.dropMask); 110 111 // 1.2. Generate mid layer of rain behind the subject. 112 rain = generateRain( 113 uvRot, 114 screenAspectRatio, 115 time * 21.4, 116 /* Grid size = */ vec2(30.0, 4.0) * gridScale, 117 intensity); 118 119 // 1.3. Blend those layers. 120 color.rgb = mix(color.rgb, highlightColor, rainVisibility * rain.dropMask); 121 122 // 1.4. Blend with the foreground. Any effect from here will be in front of the subject. 123 color.rgb = normalBlend(color.rgb, colorForeground.rgb, colorForeground.a); 124 125 // 1.5. Draw splashes 126 color.rgb = drawSplashes(uv, fragCoord, color.rgb); 127 128 // 1.6. Generate a layer of rain in front of the subject (bigger and faster). 129 rain = generateRain( 130 uvRot, 131 screenAspectRatio, 132 time * 27., 133 /* Grid size = */ vec2(8.0, 3.0) * gridScale, 134 intensity); 135 136 // Closer rain drops are less visible. 137 color.rgb = mix(color.rgb, highlightColor, 0.7 * rainVisibility * rain.dropMask); 138 139 // 2. Generate glass rain layer. 140 // 2.0. Calculate UV and add a bit of noise so that the droplets are not perfect circles. 141 float2 glassUv = vec2(valueNoise(fragCoord) * 0.015 - 0.0025) + fragCoord / screenSize; 142 143 // 2.1. Generate small glass rain. 144 GlassRain smallDrippingRain = generateGlassRain( 145 glassUv, 146 screenAspectRatio, 147 time * 0.7, 148 /* Grid size = */ vec2(5.0, 1.6) * gridScale, 149 intensity * 0.6); 150 float dropMask = smallDrippingRain.dropMask; 151 float droppletsMask = smallDrippingRain.droppletsMask; 152 float trailMask = smallDrippingRain.trailMask; 153 vec2 dropUvMasked = smallDrippingRain.drop * dropMask; 154 vec2 droppletsUvMasked = smallDrippingRain.dropplets * droppletsMask; 155 156 // 2.2. Generate medium size glass rain. 157 GlassRain medDrippingRain = generateGlassRain( 158 glassUv, 159 screenAspectRatio, 160 time * 0.80, 161 /* Grid size = */ vec2(6., 0.945) * gridScale, 162 intensity * 0.6); 163 164 // 2.3. Combine those two glass rains. 165 dropMask = max(medDrippingRain.dropMask, dropMask); 166 droppletsMask = max(medDrippingRain.droppletsMask, droppletsMask); 167 trailMask = max(medDrippingRain.trailMask, trailMask); 168 dropUvMasked = mix(dropUvMasked, 169 medDrippingRain.drop * medDrippingRain.dropMask, medDrippingRain.dropMask); 170 droppletsUvMasked = mix(droppletsUvMasked, 171 medDrippingRain.dropplets * medDrippingRain.droppletsMask, medDrippingRain.droppletsMask); 172 173 // 2.4. Add static rain droplets on the glass surface. (They stay in place and dissapate.) 174 vec2 gridSize = vec2(12., 12.) * gridScale; 175 // Aspect ratio impacts visible cells. 176 gridSize.y /= screenAspectRatio; 177 vec3 staticRain = generateStaticGlassRain(glassUv, time, intensity, gridSize); 178 dropMask = max(dropMask, staticRain.z); 179 dropUvMasked = mix(dropUvMasked, staticRain.xy * staticRain.z, staticRain.z); 180 181 // 2.5. Distort uv for the rain drops and dropplets. 182 float distortionDrop = -0.1; 183 vec2 uvDiffractionOffsets = 184 distortionDrop * dropUvMasked; 185 vec2 s = screenSize; 186 // Ensure the diffracted image in drops is not inverted. 187 s.y *= -1; 188 189 vec3 sampledColor = background.eval(uvTexture + uvDiffractionOffsets * s).rgb; 190 sampledColor = imageRangeConversion(sampledColor, 0.84, 0.02, noise, intensity); 191 color.rgb = mix(color.rgb, sampledColor, max(dropMask, droppletsMask)); 192 193 // 2.6. Add color tint to the rain drops. 194 color.rgb = mix( 195 color.rgb, 196 dropTint, 197 dropTintIntensity * smoothstep(0.7, 1., max(dropMask, droppletsMask))); 198 199 // 2.7. Add highlight to the drops. 200 color.rgb = mix( 201 color.rgb, 202 highlightColor, 203 highlightIntensity 204 * smoothstep(0.05, 0.08, max(dropUvMasked * 1.7, droppletsUvMasked * 2.6)).x); 205 206 // 2.8. Add shadows to the drops. 207 color.rgb = mix( 208 color.rgb, 209 contactShadowColor, 210 dropShadowIntensity * 211 smoothstep(0.055, 0.1, max(length(dropUvMasked * 1.7), 212 length(droppletsUvMasked * 1.9)))); 213 214 return color; 215} 216