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