Loading weathereffects/graphics/assets/shaders/glass_rain.agsl +48 −0 Original line number Diff line number Diff line Loading @@ -145,3 +145,51 @@ GlassRain generateGlassRain( return GlassRain( dropPos, cellMainDropMask, trailDropsPos, cellDroppletsMask, cellTrailMask, cellUv); } /** * Generate rain drops that stay in place on the glass surface. */ vec3 generateStaticGlassRain(vec2 uv, half screenAspectRatio, half time, half intensity) { vec2 gridSize = vec2(15., 15.); // Aspect ratio impacts visible cells. gridSize.y /= screenAspectRatio; // scale the UV to allocate number of rows and columns. vec2 gridUv = uv * gridSize; // Invert y (otherwise it goes from 0=top to 1=bottom). gridUv.y = 1. - gridUv.y; // Generate column id, to offset columns vertically (so rain is not aligned). float columnId = idGenerator(floor(gridUv.x)); gridUv.y += columnId * 5.6; // Get the cell ID based on the grid position. Value from 0 to 1. float cellId = idGenerator(floor(gridUv)); // Draw rain drops with a probability based on the cell id. if (cellId < 0.8) { return vec3(0.); } // For each cell, we set the internal UV from -0.5 (left, bottom) to 0.5 (right, top). vec2 cellUv = fract(gridUv) - 0.5; vec2 pixUv = cellUv; pixUv.x *= -1; vec2 pixDistance = screenSize * pixUv / gridSize; float delay = 3.5173; float duration = 8.2; float t = time + 100. * cellId; float circletime = floor(t / (duration + delay)); float delayOffset = idGenerator(floor(gridUv) + vec2(circletime, 43.14 * cellId)); float normalizedTime = map(/* value */ mod(t, duration + delay) - delay * delayOffset, /* in range */ 0, duration, /* out range */ 0, 1); // Apply a curve to the time. normalizedTime *= normalizedTime; vec2 pos = cellUv * (1.5 - 0.5 * cellId + normalizedTime * 50.); float mask = smoothstep(0.3, 0.2, length(pos)) * smoothstep(0.2, 0.06, normalizedTime) * smoothstep(0., 0.45, intensity); return vec3(pos * 0.19, mask); } weathereffects/graphics/assets/shaders/outline.agsl 0 → 100644 +36 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ uniform shader texture; uniform half thickness; /** * Returns whether the current fragcoord lies on the outline, return range [0, 1]. * 0 = no outline, 1 = outline * This assumes that the given texture has a transparent background and evaluates whether it's an * outline with finite differencing. */ vec4 main(float2 fragCoord) { float aN = texture.eval(fragCoord + vec2(0., thickness)).a; float aS = texture.eval(fragCoord + vec2(0., -thickness)).a; float dY = (aN - aS) * 0.5; dY = max(dY, 0.0); half outline = smoothstep(0.1, 1.8, dY * 5.0); // Return the results in the R channel. return vec4(outline, 0., 0., 0.); } weathereffects/graphics/assets/shaders/rain_glass_layer.agsl +12 −4 Original line number Diff line number Diff line Loading @@ -26,6 +26,9 @@ uniform half intensity; #include "shaders/rain_constants.agsl" vec4 main(float2 fragCoord) { // 0. Add a bit of noise so that the droplets are not perfect circles. fragCoord += vec2(valueNoise(fragCoord) * 0.015 - 0.0025); float2 uv = fragCoord / screenSize; // 1. Generate small glass rain. Loading Loading @@ -58,7 +61,12 @@ vec4 main(float2 fragCoord) { droppletsUvMasked = mix(droppletsUvMasked, medDrippingRain.dropplets * medDrippingRain.droppletsMask, medDrippingRain.droppletsMask); // 4. Distort uv for the rain drops and dropplets. // 4. Add static rain droplets on the glass surface. (They stay in place and dissapate.) vec3 staticRain = generateStaticGlassRain(uv, screenAspectRatio, time, intensity); dropMask = max(dropMask, staticRain.z); dropUvMasked = mix(dropUvMasked, staticRain.xy * staticRain.z, staticRain.z); // 5. Distort uv for the rain drops and dropplets. float distortionDrop = -0.1; vec2 uvDiffractionOffsets = distortionDrop * dropUvMasked; Loading @@ -70,20 +78,20 @@ vec4 main(float2 fragCoord) { vec3 sampledColor = texture.eval(fragCoord + uvDiffractionOffsets * s).rgb; color.rgb = mix(color.rgb, sampledColor, max(dropMask, droppletsMask)); // 5. Add color tint to the rain drops. // 6. Add color tint to the rain drops. color.rgb = mix( color.rgb, dropTint, dropTintIntensity * smoothstep(0.7, 1., max(dropMask, droppletsMask))); // 6. Add highlight to the drops. // 7. Add highlight to the drops. color.rgb = mix( color.rgb, highlightColor, highlightIntensity * smoothstep(0.05, 0.08, max(dropUvMasked * 1.7, droppletsUvMasked * 2.6)).x); // 7. Add shadows to the drops. // 8. Add shadows to the drops. color.rgb = mix( color.rgb, contactShadowColor, Loading weathereffects/graphics/assets/shaders/rain_shower_layer.agsl +50 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ uniform shader foreground; uniform shader background; uniform shader outlineBuffer; uniform float2 uvOffsetFgd; uniform float2 uvScaleFgd; uniform float2 uvOffsetBgd; Loading @@ -29,10 +30,55 @@ uniform half intensity; #include "shaders/utils.agsl" #include "shaders/rain_shower.agsl" #include "shaders/rain_constants.agsl" #include "shaders/rain_splash.agsl" // Controls how visible the rain drops are. const float rainVisibility = 0.4; /** * Draws splashes around the outline of the given image. */ vec3 drawSplashes(vec2 uv, vec2 fragCoord, vec3 color) { /** 1. Make a grid */ vec2 gridSize = vec2(15., 15.); // Aspect ratio impacts visible cells. gridSize.y /= screenAspectRatio; // Scale the UV to allocate number of rows and columns. vec2 gridUv = uv * gridSize; // Invert y (otherwise it goes from 0=top to 1=bottom). gridUv.y = 1. - gridUv.y; // Generate column id, to offset columns vertically (so rain is not aligned). float columnOffset = idGenerator(floor(gridUv.x)); gridUv.y += columnOffset * 2.6; // For each cell, we set the internal UV from -0.5 (left, bottom) to 0.5 (right, top). vec2 cellUv = fract(gridUv) - 0.5; vec2 pixUv = cellUv; pixUv.x *= -1; vec2 pixDistance = screenSize * pixUv / gridSize; float2 uvTextureFgd = (fragCoord + pixDistance) * uvScaleFgd + uvOffsetFgd; float outline = step(0.1, outlineBuffer.eval(uvTextureFgd).r); if (outline < 0.1) { // Simply return the given color when it's not considered as an outline. return color; } float t = time + 53.512 * columnOffset; float delay = 1.5173; float duration = 1.2; float circletime = floor(t / (duration + delay)); // Get the cell ID based on the grid position. [0, 1]. float cellId = idGenerator(floor(gridUv) + vec2(circletime, 23.14)); // Normalized time [0, 1]. float cellTime = max((mod(t + delay * cellId, duration + delay) - delay) / duration, 0.); float splash = drawSplash(cellUv, cellTime) * smoothstep(0., 0.45, intensity); return normalBlendWithWhiteSrc(color, splash); } vec4 main(float2 fragCoord) { float2 uv = fragCoord / screenSize; Loading Loading @@ -71,7 +117,10 @@ vec4 main(float2 fragCoord) { // 4. Blend with the foreground. Any effect from here will be in front of the subject. color.rgb = normalBlend(color.rgb, colorForeground.rgb, colorForeground.a); // 5. Generate a layer of rain in front of the subject (bigger and faster). // 5. Draw splashes color.rgb = drawSplashes(uv, fragCoord, color.rgb); // 6. Generate a layer of rain in front of the subject (bigger and faster). rain = generateRain( uv, screenAspectRatio, Loading weathereffects/graphics/assets/shaders/rain_splash.agsl 0 → 100644 +94 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Draw a single splash. * @param cellUv Range of [-0.5, 0.5]: left bottom (-0.5, -0.5), right top (0.5, 0.5). * @param cellTime Normalized cellTime range of [0, 1]. */ float drawSplash(vec2 cellUv, float cellTime) { /** 0. Adjust UV and time. */ cellUv = cellUv * 0.5; cellUv += 0.1; float t = 0.408 + cellTime * 4.; /** 1. Start of drawing a splash */ // Draw one side of a splash (a crescent) using two circles, by overlapping them with a slight // offset. Then we reflect the splash to get the full splash. // Reflect the splash. vec2 uvAbs = abs(cellUv); // Center of the splash (of the right splash) vec2 center = vec2(0.22, -0.01); float splashMaskCircle1 = sdfCircle(uvAbs - center, 0.164); float splashMaskCircle2 = sdfCircle(uvAbs - vec2(0.04, 0.) - center, 0.164); splashMaskCircle1 = smoothstep(0.052, 0.12, splashMaskCircle1); splashMaskCircle2 = smoothstep(0.1, 0.152, splashMaskCircle2); // Here, we have a full splash that covers the entire cell float splash = splashMaskCircle1 - splashMaskCircle2; // Mask the splash so that it doesn't cover the entire cell. float circleMask = sdfCircle(cellUv - vec2(0., 0.15), -0.004); float splashColor = splash * smoothstep(0.152, 0.1, circleMask); // Another mask for the splash to reveal it vertically. float maskThickHalf = 0.052; float maskFade = 0.05; vec2 maskMiddle = vec2(-0.1, -0.5); maskMiddle.y *= sin(mod(t, 4.4)); float mask = smoothstep(maskMiddle.y - maskThickHalf - maskFade, maskMiddle.y - maskThickHalf, cellUv.y) - smoothstep(maskMiddle.y + maskThickHalf, maskMiddle.y + maskThickHalf + maskFade, cellUv.y); splashColor *= mask; /** End of drawing a splash */ /** 2. Start of drawing a vertical line of the splash */ // Draw the vertical line. float verticalLine = 0.035; float lineCenter = 0.192; float lineColor = 0.4 * (smoothstep(-verticalLine, 0., cellUv.x) - smoothstep(0., verticalLine, cellUv.x)) * smoothstep(0.008, -0.156, sdfCircle(cellUv - vec2(0., lineCenter), 0.164)); // Mask the vertical line to reveal it vertically. float lineMaskThickHalf = 0.124; float lineMaskFade = 0.170; vec2 lineMaskMiddle = vec2(-0.01, 2.71); lineMaskMiddle.y *= sin(mod(t, 4.4) - 0.168); float lineMask = smoothstep(lineMaskMiddle.y - lineMaskThickHalf - lineMaskFade, lineMaskMiddle.y - lineMaskThickHalf, cellUv.y) - smoothstep(lineMaskMiddle.y + lineMaskThickHalf, lineMaskMiddle.y + lineMaskThickHalf + lineMaskFade, cellUv.y); float line = lineColor * lineMask; /** End of drawing the vertical line of the splash */ /** 3. Composite the splash and the line. */ return splashColor * (1. - line) + line; } Loading
weathereffects/graphics/assets/shaders/glass_rain.agsl +48 −0 Original line number Diff line number Diff line Loading @@ -145,3 +145,51 @@ GlassRain generateGlassRain( return GlassRain( dropPos, cellMainDropMask, trailDropsPos, cellDroppletsMask, cellTrailMask, cellUv); } /** * Generate rain drops that stay in place on the glass surface. */ vec3 generateStaticGlassRain(vec2 uv, half screenAspectRatio, half time, half intensity) { vec2 gridSize = vec2(15., 15.); // Aspect ratio impacts visible cells. gridSize.y /= screenAspectRatio; // scale the UV to allocate number of rows and columns. vec2 gridUv = uv * gridSize; // Invert y (otherwise it goes from 0=top to 1=bottom). gridUv.y = 1. - gridUv.y; // Generate column id, to offset columns vertically (so rain is not aligned). float columnId = idGenerator(floor(gridUv.x)); gridUv.y += columnId * 5.6; // Get the cell ID based on the grid position. Value from 0 to 1. float cellId = idGenerator(floor(gridUv)); // Draw rain drops with a probability based on the cell id. if (cellId < 0.8) { return vec3(0.); } // For each cell, we set the internal UV from -0.5 (left, bottom) to 0.5 (right, top). vec2 cellUv = fract(gridUv) - 0.5; vec2 pixUv = cellUv; pixUv.x *= -1; vec2 pixDistance = screenSize * pixUv / gridSize; float delay = 3.5173; float duration = 8.2; float t = time + 100. * cellId; float circletime = floor(t / (duration + delay)); float delayOffset = idGenerator(floor(gridUv) + vec2(circletime, 43.14 * cellId)); float normalizedTime = map(/* value */ mod(t, duration + delay) - delay * delayOffset, /* in range */ 0, duration, /* out range */ 0, 1); // Apply a curve to the time. normalizedTime *= normalizedTime; vec2 pos = cellUv * (1.5 - 0.5 * cellId + normalizedTime * 50.); float mask = smoothstep(0.3, 0.2, length(pos)) * smoothstep(0.2, 0.06, normalizedTime) * smoothstep(0., 0.45, intensity); return vec3(pos * 0.19, mask); }
weathereffects/graphics/assets/shaders/outline.agsl 0 → 100644 +36 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ uniform shader texture; uniform half thickness; /** * Returns whether the current fragcoord lies on the outline, return range [0, 1]. * 0 = no outline, 1 = outline * This assumes that the given texture has a transparent background and evaluates whether it's an * outline with finite differencing. */ vec4 main(float2 fragCoord) { float aN = texture.eval(fragCoord + vec2(0., thickness)).a; float aS = texture.eval(fragCoord + vec2(0., -thickness)).a; float dY = (aN - aS) * 0.5; dY = max(dY, 0.0); half outline = smoothstep(0.1, 1.8, dY * 5.0); // Return the results in the R channel. return vec4(outline, 0., 0., 0.); }
weathereffects/graphics/assets/shaders/rain_glass_layer.agsl +12 −4 Original line number Diff line number Diff line Loading @@ -26,6 +26,9 @@ uniform half intensity; #include "shaders/rain_constants.agsl" vec4 main(float2 fragCoord) { // 0. Add a bit of noise so that the droplets are not perfect circles. fragCoord += vec2(valueNoise(fragCoord) * 0.015 - 0.0025); float2 uv = fragCoord / screenSize; // 1. Generate small glass rain. Loading Loading @@ -58,7 +61,12 @@ vec4 main(float2 fragCoord) { droppletsUvMasked = mix(droppletsUvMasked, medDrippingRain.dropplets * medDrippingRain.droppletsMask, medDrippingRain.droppletsMask); // 4. Distort uv for the rain drops and dropplets. // 4. Add static rain droplets on the glass surface. (They stay in place and dissapate.) vec3 staticRain = generateStaticGlassRain(uv, screenAspectRatio, time, intensity); dropMask = max(dropMask, staticRain.z); dropUvMasked = mix(dropUvMasked, staticRain.xy * staticRain.z, staticRain.z); // 5. Distort uv for the rain drops and dropplets. float distortionDrop = -0.1; vec2 uvDiffractionOffsets = distortionDrop * dropUvMasked; Loading @@ -70,20 +78,20 @@ vec4 main(float2 fragCoord) { vec3 sampledColor = texture.eval(fragCoord + uvDiffractionOffsets * s).rgb; color.rgb = mix(color.rgb, sampledColor, max(dropMask, droppletsMask)); // 5. Add color tint to the rain drops. // 6. Add color tint to the rain drops. color.rgb = mix( color.rgb, dropTint, dropTintIntensity * smoothstep(0.7, 1., max(dropMask, droppletsMask))); // 6. Add highlight to the drops. // 7. Add highlight to the drops. color.rgb = mix( color.rgb, highlightColor, highlightIntensity * smoothstep(0.05, 0.08, max(dropUvMasked * 1.7, droppletsUvMasked * 2.6)).x); // 7. Add shadows to the drops. // 8. Add shadows to the drops. color.rgb = mix( color.rgb, contactShadowColor, Loading
weathereffects/graphics/assets/shaders/rain_shower_layer.agsl +50 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ uniform shader foreground; uniform shader background; uniform shader outlineBuffer; uniform float2 uvOffsetFgd; uniform float2 uvScaleFgd; uniform float2 uvOffsetBgd; Loading @@ -29,10 +30,55 @@ uniform half intensity; #include "shaders/utils.agsl" #include "shaders/rain_shower.agsl" #include "shaders/rain_constants.agsl" #include "shaders/rain_splash.agsl" // Controls how visible the rain drops are. const float rainVisibility = 0.4; /** * Draws splashes around the outline of the given image. */ vec3 drawSplashes(vec2 uv, vec2 fragCoord, vec3 color) { /** 1. Make a grid */ vec2 gridSize = vec2(15., 15.); // Aspect ratio impacts visible cells. gridSize.y /= screenAspectRatio; // Scale the UV to allocate number of rows and columns. vec2 gridUv = uv * gridSize; // Invert y (otherwise it goes from 0=top to 1=bottom). gridUv.y = 1. - gridUv.y; // Generate column id, to offset columns vertically (so rain is not aligned). float columnOffset = idGenerator(floor(gridUv.x)); gridUv.y += columnOffset * 2.6; // For each cell, we set the internal UV from -0.5 (left, bottom) to 0.5 (right, top). vec2 cellUv = fract(gridUv) - 0.5; vec2 pixUv = cellUv; pixUv.x *= -1; vec2 pixDistance = screenSize * pixUv / gridSize; float2 uvTextureFgd = (fragCoord + pixDistance) * uvScaleFgd + uvOffsetFgd; float outline = step(0.1, outlineBuffer.eval(uvTextureFgd).r); if (outline < 0.1) { // Simply return the given color when it's not considered as an outline. return color; } float t = time + 53.512 * columnOffset; float delay = 1.5173; float duration = 1.2; float circletime = floor(t / (duration + delay)); // Get the cell ID based on the grid position. [0, 1]. float cellId = idGenerator(floor(gridUv) + vec2(circletime, 23.14)); // Normalized time [0, 1]. float cellTime = max((mod(t + delay * cellId, duration + delay) - delay) / duration, 0.); float splash = drawSplash(cellUv, cellTime) * smoothstep(0., 0.45, intensity); return normalBlendWithWhiteSrc(color, splash); } vec4 main(float2 fragCoord) { float2 uv = fragCoord / screenSize; Loading Loading @@ -71,7 +117,10 @@ vec4 main(float2 fragCoord) { // 4. Blend with the foreground. Any effect from here will be in front of the subject. color.rgb = normalBlend(color.rgb, colorForeground.rgb, colorForeground.a); // 5. Generate a layer of rain in front of the subject (bigger and faster). // 5. Draw splashes color.rgb = drawSplashes(uv, fragCoord, color.rgb); // 6. Generate a layer of rain in front of the subject (bigger and faster). rain = generateRain( uv, screenAspectRatio, Loading
weathereffects/graphics/assets/shaders/rain_splash.agsl 0 → 100644 +94 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * Draw a single splash. * @param cellUv Range of [-0.5, 0.5]: left bottom (-0.5, -0.5), right top (0.5, 0.5). * @param cellTime Normalized cellTime range of [0, 1]. */ float drawSplash(vec2 cellUv, float cellTime) { /** 0. Adjust UV and time. */ cellUv = cellUv * 0.5; cellUv += 0.1; float t = 0.408 + cellTime * 4.; /** 1. Start of drawing a splash */ // Draw one side of a splash (a crescent) using two circles, by overlapping them with a slight // offset. Then we reflect the splash to get the full splash. // Reflect the splash. vec2 uvAbs = abs(cellUv); // Center of the splash (of the right splash) vec2 center = vec2(0.22, -0.01); float splashMaskCircle1 = sdfCircle(uvAbs - center, 0.164); float splashMaskCircle2 = sdfCircle(uvAbs - vec2(0.04, 0.) - center, 0.164); splashMaskCircle1 = smoothstep(0.052, 0.12, splashMaskCircle1); splashMaskCircle2 = smoothstep(0.1, 0.152, splashMaskCircle2); // Here, we have a full splash that covers the entire cell float splash = splashMaskCircle1 - splashMaskCircle2; // Mask the splash so that it doesn't cover the entire cell. float circleMask = sdfCircle(cellUv - vec2(0., 0.15), -0.004); float splashColor = splash * smoothstep(0.152, 0.1, circleMask); // Another mask for the splash to reveal it vertically. float maskThickHalf = 0.052; float maskFade = 0.05; vec2 maskMiddle = vec2(-0.1, -0.5); maskMiddle.y *= sin(mod(t, 4.4)); float mask = smoothstep(maskMiddle.y - maskThickHalf - maskFade, maskMiddle.y - maskThickHalf, cellUv.y) - smoothstep(maskMiddle.y + maskThickHalf, maskMiddle.y + maskThickHalf + maskFade, cellUv.y); splashColor *= mask; /** End of drawing a splash */ /** 2. Start of drawing a vertical line of the splash */ // Draw the vertical line. float verticalLine = 0.035; float lineCenter = 0.192; float lineColor = 0.4 * (smoothstep(-verticalLine, 0., cellUv.x) - smoothstep(0., verticalLine, cellUv.x)) * smoothstep(0.008, -0.156, sdfCircle(cellUv - vec2(0., lineCenter), 0.164)); // Mask the vertical line to reveal it vertically. float lineMaskThickHalf = 0.124; float lineMaskFade = 0.170; vec2 lineMaskMiddle = vec2(-0.01, 2.71); lineMaskMiddle.y *= sin(mod(t, 4.4) - 0.168); float lineMask = smoothstep(lineMaskMiddle.y - lineMaskThickHalf - lineMaskFade, lineMaskMiddle.y - lineMaskThickHalf, cellUv.y) - smoothstep(lineMaskMiddle.y + lineMaskThickHalf, lineMaskMiddle.y + lineMaskThickHalf + lineMaskFade, cellUv.y); float line = lineColor * lineMask; /** End of drawing the vertical line of the splash */ /** 3. Composite the splash and the line. */ return splashColor * (1. - line) + line; }