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 accumulatedSnow; 20uniform shader noise; 21uniform float2 gridSize; 22uniform float time; 23uniform float screenAspectRatio; 24uniform float2 screenSize; 25uniform mat3 transformMatrixBitmap; 26uniform mat3 transformMatrixWeather; 27 28#include "shaders/constants.agsl" 29#include "shaders/utils.agsl" 30#include "shaders/snow.agsl" 31 32// Snow tint. 33const vec4 snowColor = vec4(1., 1., 1., 0.95); 34// Background tint 35const vec4 bgdTint = vec4(0.8, 0.8, 0.8, 0.07); 36 37// Indices of the different snow layers. 38const float farthestSnowLayerIndex = 6; 39const float midSnowLayerIndex = 2; 40const float closestSnowLayerIndex = 0; 41 42vec4 main(float2 fragCoord) { 43 /** 44 * The effect is consisted of 2 image textures (foreground and background) + 10 layers of 45 * snow + 1 layer of snow accumulation. Below describes the rendering order (back to front): 46 * 1. Background 47 * 2. Background snow layers (from farthest layer to mid layer) 48 * 3. Foreground 49 * 4. Snow accumulation layer (on subject) 50 * 5. Foreground snow layers (from mid layer to closest layer) 51 */ 52 53 // Apply transform matrix to fragCoord 54 float2 adjustedUv = transformPoint(transformMatrixBitmap, fragCoord); 55 // Calculate uv for snow based on transformed coordinates 56 float2 uv = transformPoint(transformMatrixWeather, fragCoord) / screenSize; 57 float2 uvAdjusted = vec2(uv.x, uv.y / screenAspectRatio); 58 59 vec4 colorForeground = foreground.eval(adjustedUv); 60 vec4 colorBackground = background.eval(adjustedUv); 61 62 // Adjusts contrast and brightness. 63 float noiseT = triangleNoise(fragCoord.xy + vec2(12.31, 1024.1241)); 64 colorBackground.rgb = 65 imageRangeConversion(colorBackground.rgb, 0.88, 0.02, noiseT * 0.025, intensity); 66 colorForeground.rgb = 67 imageRangeConversion(colorForeground.rgb, 0.88, 0.02, noiseT * 0.025, intensity); 68 69 // 1. Draw background. 70 vec4 color = colorBackground; 71 72 // Add slight tint to the background. 73 color.rgb = normalBlendNotPremultiplied(color.rgb, bgdTint.rgb, bgdTint.a); 74 75 // 2. Generate snow layers behind the subject. 76 if (colorForeground.a == 0) { 77 for (float i = farthestSnowLayerIndex; i > midSnowLayerIndex; i--) { 78 Snow snow = generateSnow( 79 uv, 80 screenAspectRatio, 81 time, 82 gridSize, 83 /* layer number = */ i, 84 closestSnowLayerIndex, 85 farthestSnowLayerIndex); 86 87 color.rgb = 88 normalBlendNotPremultiplied(color.rgb, snowColor.rgb, snowColor.a * snow.flakeMask); 89 } 90 } 91 92 // 3. Add the foreground layer. Any effect from here will be in front of the subject. 93 color.rgb = normalBlend(color.rgb, colorForeground.rgb, colorForeground.a); 94 95 // 4. Add accumulated snow layer. 96 // Load noise texture to give "fluffy-ness" to the snow. Displace the sampling of the noise. 97 vec3 cloudsNoise = noise.eval(uvAdjusted * 7000 + vec2(fragCoord.y, -fragCoord.x)).rgb; 98 // Add dither to give texture to the snow and ruffle the edges. 99 float dither = abs(triangleNoise(fragCoord * 0.01)); 100 101 // Get the accumulated snow buffer. r contains its mask, g contains some random noise. 102 vec2 accSnow = accumulatedSnow.eval(adjustedUv).rg; 103 // Sharpen the mask of the accumulated snow, but not in excess. 104 float accSnowMask = smoothstep( (1.-intensity), 1.0, /* mask= */accSnow.r); 105 if (accSnowMask > 0) { 106 // Makes the edges of the snow layer accumulation rougher. 107 accSnowMask = map(accSnowMask, 1. - cloudsNoise.b - 0.3 * dither, 1., 0., 1.); 108 // Load snow texture and dither. Make it have gray-ish values. 109 float accSnowTexture = smoothstep(0.2, 0.7, /* noise= */ accSnow.g) * 0.7; 110 accSnowTexture = map(accSnowTexture, dither - 1, 1, 0, 1); 111 // Adjust snow texture coverage/shape. 112 accSnowTexture = map(accSnowTexture, 0.67, 0.8, 0, 1); 113 accSnowMask = map(accSnowMask, 0., 1., 0., 1.- 0.6 * accSnowTexture - 0.35 * dither); 114 115 color.rgb = normalBlendNotPremultiplied(color.rgb, snowColor.rgb, snowColor.a * accSnowMask); 116 } 117 118 // 5. Generate snow in front of the subject. 119 for (float i = midSnowLayerIndex; i >= closestSnowLayerIndex; i--) { 120 Snow snow = generateSnow( 121 uv, 122 screenAspectRatio, 123 time, 124 gridSize, 125 /* layer number = */ i, 126 closestSnowLayerIndex, 127 farthestSnowLayerIndex); 128 129 color.rgb = 130 normalBlendNotPremultiplied(color.rgb, snowColor.rgb, snowColor.a * snow.flakeMask); 131 } 132 133 return color; 134} 135