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 = 9; 39const float midSnowLayerIndex = 3; 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 56 // Calculate uv for snow based on transformed coordinates 57 float2 uv = transformPoint(transformMatrixWeather, fragCoord) / screenSize; 58 float2 uvAdjusted = vec2(uv.x, uv.y / screenAspectRatio); 59 60 vec4 colorForeground = foreground.eval(adjustedUv); 61 vec4 colorBackground = background.eval(adjustedUv); 62 63 // Adjusts contrast and brightness. 64 float noiseT = triangleNoise(fragCoord.xy + vec2(12.31, 1024.1241)); 65 colorBackground.rgb = 66 imageRangeConversion(colorBackground.rgb, 0.88, 0.02, noiseT * 0.025, intensity); 67 colorForeground.rgb = 68 imageRangeConversion(colorForeground.rgb, 0.88, 0.02, noiseT * 0.025, intensity); 69 70 // 1. Draw background. 71 vec4 color = colorBackground; 72 73 // Add slight tint to the background. 74 color.rgb = normalBlendNotPremultiplied(color.rgb, bgdTint.rgb, bgdTint.a); 75 76 // 2. Generate snow layers behind the subject. 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 // 3. Add the foreground layer. Any effect from here will be in front of the subject. 92 color.rgb = normalBlend(color.rgb, colorForeground.rgb, colorForeground.a); 93 94 // 4. Add accumulated snow layer. 95 // Load noise texture to give "fluffy-ness" to the snow. Displace the sampling of the noise. 96 vec3 cloudsNoise = noise.eval(uvAdjusted * 7000 + vec2(fragCoord.y, -fragCoord.x)).rgb; 97 // Add dither to give texture to the snow and ruffle the edges. 98 float dither = abs(triangleNoise(fragCoord * 0.01)); 99 100 // Get the accumulated snow buffer. r contains its mask, g contains some random noise. 101 vec2 accSnow = accumulatedSnow.eval(adjustedUv).rg; 102 // Sharpen the mask of the accumulated snow, but not in excess. 103 float accSnowMask = smoothstep(0.1, 0.9, /* mask= */ accSnow.r); 104 // Makes the edges of the snow layer accumulation rougher. 105 accSnowMask = map(accSnowMask, 1. - cloudsNoise.b - 0.3 * dither, 1., 0., 1.); 106 // Load snow texture and dither. Make it have gray-ish values. 107 float accSnowTexture = smoothstep(0.2, 0.7, /* noise= */ accSnow.g) * 0.7; 108 accSnowTexture = map(accSnowTexture, dither - 1, 1, 0, 1); 109 // Adjust snow texture coverage/shape. 110 accSnowTexture = map(accSnowTexture, 0.67, 0.8, 0, 1); 111 accSnowMask = map(accSnowMask, 0., 1., 0., 1.- 0.6 * accSnowTexture - 0.35 * dither); 112 113 color.rgb = normalBlendNotPremultiplied(color.rgb, snowColor.rgb, snowColor.a * accSnowMask); 114 115 // 5. Generate snow in front of the subject. 116 for (float i = midSnowLayerIndex; i >= closestSnowLayerIndex; i--) { 117 Snow snow = generateSnow( 118 uv, 119 screenAspectRatio, 120 time, 121 gridSize, 122 /* layer number = */ i, 123 closestSnowLayerIndex, 124 farthestSnowLayerIndex); 125 126 color.rgb = 127 normalBlendNotPremultiplied(color.rgb, snowColor.rgb, snowColor.a * snow.flakeMask); 128 } 129 130 return color; 131} 132