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 float screenAspectRatio; 20uniform float2 screenSize; 21uniform float time; 22uniform float intensity; 23uniform mat3 transformMatrixBitmap; 24uniform mat3 transformMatrixWeather; 25 26 27#include "shaders/constants.agsl" 28#include "shaders/utils.agsl" 29#include "shaders/simplex3d.agsl" 30 31#include "shaders/lens_flare.agsl" 32 33const vec2 sunCenter = vec2(0.57, -0.8); 34const vec3 godRaysColor = vec3(1., 0.857, 0.71428); 35 36float calculateRay(float angle, float time) { 37 /* 38 * God rays oscilations. It works like a fourier series, using the the uv position angle 39 * and time and phase to adjust how it looks. 40 */ 41 float rays = 17.5 + 8.0 * sin(3. * angle + time); 42 rays += 4.0 * sin(12. * angle - 0.3 * time); 43 rays += 4.0 * sin(25. * angle + 0.9252 * time); 44 rays += -1.8 * cos(38. * angle - 0.114 * time); 45 rays += 0.45 * cos(60.124 * angle + 0.251 * time); 46 return rays; 47} 48 49float godRays(vec2 uv, vec2 center, float phase, float frequency, float time, float intensity) { 50 // Adjust position to center. 51 uv -= center; 52 // For each position, get the angle. 53 float angle = atan(uv.y, uv.x); 54 // The glow around the position of the sun. 55 float sunGlow = 1.0 / (1. + 20.0 * length(uv)); 56 float rays = calculateRay(angle * frequency, phase + time); 57 return intensity * sunGlow * (rays * 0.4 + 2 + 2 * length(uv)); 58} 59 60vec3 addGodRays( 61 vec3 background, 62 vec2 fragCoord, 63 vec2 uv, 64 vec2 sunPos, 65 float phase, 66 float frequency, 67 float timeSpeed) { 68 float rays = 69 godRays( 70 uv, 71 sunPos, 72 phase, 73 frequency, 74 timeSpeed * time, 75 intensity); 76 // Dithering. 77 rays -= triangleNoise(fragCoord.xy) * 0.025; 78 rays = clamp(rays, 0., 1.); 79 vec3 raysColor = mix(godRaysColor, min(godRaysColor + 0.5, vec3(1)), smoothstep(0.15, 0.6, rays)); 80 return normalBlendNotPremultiplied(background.rgb, raysColor, smoothstep(0.1, 1., rays)); 81} 82 83float checkBrightnessGodRaysAtCenter( 84 vec2 center, 85 float phase, 86 float frequency, 87 float timeSpeed) { 88 // For each position, get the angle. 89 float angle = atan(-center.y, -center.x); 90 float rays = calculateRay(angle * frequency, phase + timeSpeed * time); 91 // Normalize [0, 1] the brightness. 92 return smoothstep(-0.75, 35.25, rays); 93 94} 95 96vec4 main(float2 fragCoord) { 97 // Apply transform matrix to fragCoord 98 float2 adjustedUv = transformPoint(transformMatrixBitmap, fragCoord); 99 100 float2 uv = transformPoint(transformMatrixWeather, fragCoord) / screenSize; 101 uv -= vec2(0.5, 0.5); 102 uv.y /= screenAspectRatio; 103 vec2 sunVariation = vec2(0.1 * sin(time * 0.3), 0.14 * cos(time * 0.5)); 104 sunVariation += 0.1 * (0.5 * sin(time * 0.456) + 0.5) * sunCenter / vec2(1., screenAspectRatio); 105 vec2 sunPos = sunVariation + sunCenter / vec2(1., screenAspectRatio); 106 //TODO(b/375214506): fix the uv position of the sun 107 108 vec4 colorForeground = foreground.eval(adjustedUv); 109 vec4 color = background.eval(adjustedUv); 110 // add foreground 111 color.rgb = normalBlend(color.rgb, colorForeground.rgb, colorForeground.a); 112 113 // Calculate brightness from sunrays. 114 float brightnessSunray = checkBrightnessGodRaysAtCenter(sunPos, 10.0, 1.1, 0.9); 115 brightnessSunray *= brightnessSunray; 116 117 // Adjusts contrast and brightness. 118 float noise = 0.025 * triangleNoise(fragCoord.xy + vec2(12.31, 1024.1241)); 119 color.rgb = imageRangeConversion(color.rgb, 0.88, 0.02, noise, intensity); 120 121 // Adjust color grading for shadows and highlights. 122 float lum = relativeLuminance(color.rgb); 123 vec3 highlightColor = vec3(0.41, 0.69, 0.856); 124 float highlightThres = 0.66; 125 float highlightBlend = 0.30 + + brightnessSunray * 0.1; 126 vec3 shadowColor = vec3(0.756, 0.69, 0.31); 127 float shadowThres = 0.33; 128 float shadowBlend = 0.2 + brightnessSunray * 0.1; 129 130 float highlightsMask = smoothstep(highlightThres, 1., lum); 131 float shadowsMask = 1. - smoothstep(0., shadowThres, lum); 132 133 color.rgb = normalBlendNotPremultiplied( 134 color.rgb, shadowColor, intensity * shadowBlend * shadowsMask); 135 color.rgb = normalBlendNotPremultiplied( 136 color.rgb, highlightColor, intensity * highlightBlend * highlightsMask); 137 138 // Add god rays. 139 color.rgb = addGodRays(color.rgb, fragCoord.xy, uv, sunPos, 10.0, 1.1, 0.9); 140 // Add flare. 141 color.rgb = addFlare(color.rgb, uv, sunPos, (0.4 + 0.8 * brightnessSunray) * intensity, time); 142 return color; 143} 144