Loading weathereffects/graphics/assets/shaders/snow.agsl +54 −21 Original line number Diff line number Diff line Loading @@ -19,12 +19,15 @@ struct Snow { highp vec2 cellUv; }; const vec2 snowFlakeShape = vec2(0.28, 0.26); // decreasedFactor should match minDescreasedFactor * 2, minDescreasedFactor is defined in snow_flake_samples.agsl const float decreasedFactor = 1.0 / 0.28; const mat2 rot45 = mat2( 0.7071067812, 0.7071067812, // First column. -0.7071067812, 0.7071067812 // second column. ); uniform half intensity; uniform half snowFlakeSamplesSize; const float farthestSnowLayerWiggleSpeed = 2.18; const float closestSnowLayerWiggleSpeed = 0.9; /** * Generates snow flakes. Loading @@ -50,14 +53,18 @@ Snow generateSnow( in float minLayerIndex, in float maxLayerIndex ) { // Normalize the layer index. 0 is closest, 1 is farthest. half normalizedLayerIndex = map(layerIndex, minLayerIndex, maxLayerIndex, 0, 1); /* Grid. */ // Increase the last number to make each layer more separate from the previous one. float depth = 0.65 + layerIndex * 0.755; float depth = 0.65 + layerIndex * 0.555; float speedAdj = 1. + layerIndex * 0.225; float layerR = idGenerator(layerIndex); snowGridSize *= depth; time += layerR * 58.3; // Number of rows and columns (each one is a cell, a drop). float cellAspectRatio = snowGridSize.x / snowGridSize.y; // Aspect ratio impacts visible cells. uv.y /= screenAspectRatio; // Skew uv.x so it goes to left or right Loading @@ -74,34 +81,60 @@ Snow generateSnow( // Have time affect the position of each column as well. gridUv.y += columnId * 2.6 + time * 0.19 * (1 - columnId); // Calclulate the grid this pixel belonging to, and also the offset in the cell. vec2 gridIdx = floor(gridUv); /* Cell. */ // Get the cell ID based on the grid position. Value from 0 to 1. float cellId = idGenerator(floor(gridUv)); // For each cell, we set the internal UV from -0.5 (left, bottom) to 0.5 (right, top). vec2 cellUv = fract(gridUv) - 0.5; cellUv.y *= -1.; // The bigger the decreasedFactor, the smaller the snow flake. vec2 snowFlakePos = vec2(cellUv.x, cellUv.y * (snowGridSize.x / snowGridSize.y - 1.0 / snowGridSize.y) + uv.y - 0.5 / screenAspectRatio) * decreasedFactor; if (abs(snowFlakePos.y) > 0.5 || abs(snowFlakePos.x) > 0.5 ) { return Snow(/* flakeMask= */ 0, cellUv); } vec4 color = snowFlakeSamples.eval(snowFlakeSamplesSize * (gridIdx - 0.5 + snowFlakePos)); float baseMask = color.r; half cellIntensity = color.g; float cellId = color.b; if (cellIntensity <= 1. - intensity) { // Remove snow flakes by seting flake mask to 0. /* * Disable snow flakes with some probabilty. This is done by 1) assigning a random intensity * value to the cell 2) then compare it with the given intensity. */ half cellIntensity = idGenerator(floor(vec2(cellId * 856.16, 272.2))); if (cellIntensity < 1. - intensity) { // Remove snow flakes by seeting flake mask to 0. return Snow(/* flakeMask= */ 0, cellUv); } /* Cell-id-based variations. */ // 0 = snow flake invisible, 1 = snow flake visible. float visibilityFactor = smoothstep( cellIntensity, max(cellIntensity - (0.02 + 0.18 * intensity), 0.0), 1 - intensity); // Adjust the size of each snow flake (higher is smaller) based on cell ID. float decreaseFactor = 2.0 + map(cellId, 0., 1., -0.1, 2.8) + 5. * (1 - visibilityFactor); // Adjust the opacity of the particle based on the cell id and distance from the camera. float farLayerFadeOut = map(normalizedLayerIndex, 0.7, 1, 1, 0.4); float closeLayerFadeOut = map(normalizedLayerIndex, 0, 0.2, 0.6, 1); float opacityVariation = (1. - 0.9 * cellId) * visibilityFactor * farLayerFadeOut * closeLayerFadeOut; float flakeMask = baseMask * opacityVariation; visibilityFactor * closeLayerFadeOut * farLayerFadeOut; /* Cell snow flake. */ // Calculate snow flake. vec2 snowFlakeShape = vec2(0.28, 0.26); vec2 snowFlakePos = vec2(cellUv.x, cellUv.y * cellAspectRatio); snowFlakePos -= vec2( 0., (uv.y - 0.5 / screenAspectRatio) - cellUv.y / snowGridSize.y ) * screenAspectRatio; snowFlakePos *= snowFlakeShape * decreaseFactor; vec2 snowFlakeShapeVariation = vec2(0.055) * // max variation vec2((cellId * 2. - 1.), // random A based on cell ID (fract((cellId + 0.03521) * 34.21) * 2. - 1.)); // random B based on cell ID vec2 snowFlakePosR = 1.016 * abs(rot45 * (snowFlakePos + snowFlakeShapeVariation)); snowFlakePos = abs(snowFlakePos); // Create the snowFlake mask. float flakeMask = smoothstep( 0.3, 0.200 - 0.3 * opacityVariation, snowFlakePos.x + snowFlakePos.y + snowFlakePosR.x + snowFlakePosR.y ) * opacityVariation; return Snow(flakeMask, cellUv); } weathereffects/graphics/assets/shaders/snow_effect.agsl +2 −6 Original line number Diff line number Diff line Loading @@ -21,10 +21,8 @@ uniform float2 gridSize; uniform float time; uniform float screenAspectRatio; uniform float2 screenSize; uniform float cellAspectRatio; uniform mat3 transformMatrixBitmap; uniform mat3 transformMatrixWeather; uniform shader snowFlakeSamples; #include "shaders/constants.agsl" #include "shaders/utils.agsl" Loading @@ -32,13 +30,11 @@ uniform shader snowFlakeSamples; // Snow tint. const vec4 snowColor = vec4(1., 1., 1., 0.95); // Background tint const vec4 bgdTint = vec4(0.8, 0.8, 0.8, 0.07); // Indices of the different snow layers. const float farthestSnowLayerIndex = 4; const float farthestSnowLayerIndex = 6; const float midSnowLayerIndex = 2; const float closestSnowLayerIndex = 0; Loading weathereffects/graphics/assets/shaders/snow_flake_samples.agsldeleted 100644 → 0 +0 −79 Original line number Diff line number Diff line /* * Copyright (C) 2025 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 float2 canvasSize; uniform float snowFlakeSamplesSize; #include "shaders/constants.agsl" #include "shaders/utils.agsl" const vec2 snowFlakeShape = vec2(0.28, 0.26); // Used in generate snow flake samples, and sampling it afterwards, to make sure snow flakes // will not go beyond bounding box const float minDecreaseFactor = 0.5 / 0.28; const float layerIndex = 0; const mat2 rot45 = mat2( 0.7071067812, 0.7071067812, // First column. -0.7071067812, 0.7071067812 // second column. ); /** * This shader generates snow flake samples per cell. It stores the flake mask in the red channel, * and pre-calculated `cellIntensity` and `cellId` in the green and blue channels for optimized access. */ vec4 main(float2 fragCoord) { // Calculate uv for snow based on transformed coordinates float2 uv = fragCoord / canvasSize; float layerR = idGenerator(layerIndex); // Number of rows and columns (each one is a cell, a snowflake). vec2 gridSize = floor(canvasSize / snowFlakeSamplesSize); float cellAspectRatio = gridSize.x / gridSize.y; // Aspect ratio impacts visible cells. vec2 gridUv = uv * gridSize; /* Cell. */ // Get the cell ID based on the grid position. Value from 0 to 1. float cellId = idGenerator(floor(gridUv)); // For each cell, we set the internal UV from -0.5 (left, bottom) to 0.5 (right, top). vec2 cellUv = fract(gridUv) - 0.5; cellUv.y *= -1.; /* * Disable snow flakes with some probabilty. This is done by 1) assigning a random intensity * value to the cell 2) then compare it with the given intensity. */ half cellIntensity = idGenerator(floor(vec2(cellId * 856.16, 272.2))); /* Cell snow flake. */ // Calculate snow flake. // With decreaseFactor <= minSnowShapeScale, we can make sure snow flakes not going out its // snowFlakeSamplesSize * snowFlakeSamplesSize bounding box float decreaseFactor = clamp(2.0 + map(cellId, 0., 1., 1., 1 + 5. * (1 - cellIntensity)), minDecreaseFactor, 4); // snowFlake center should be (0,0) in the cell when generating snowflake samples vec2 snowFlakePos = vec2(cellUv.x, cellUv.y); snowFlakePos *= snowFlakeShape * decreaseFactor; vec2 snowFlakeShapeVariation = vec2(0.055) * // max variation vec2((cellId * 2. - 1.), // random A based on cell ID (fract((cellId + 0.03521) * 34.21) * 2. - 1.)); // random B based on cell ID vec2 snowFlakePosR = 1.016 * abs(rot45 * (snowFlakePos + snowFlakeShapeVariation)); snowFlakePos = abs(snowFlakePos); // Create the snowFlake mask. float baseMask = 1 - clamp(snowFlakePos.x + snowFlakePos.y + snowFlakePosR.x + snowFlakePosR.y, 0, 1); return vec4(baseMask, cellIntensity, cellId , 1); } weathereffects/graphics/assets/shaders/utils.agsl +0 −4 Original line number Diff line number Diff line Loading @@ -150,7 +150,3 @@ float2 transformPoint(mat3 transformMatrix, float2 point) { // Convert back to Cartesian coordinates (x, y) return transformedPoint.xy / transformedPoint.z; } float normalizeValue(float x, float minVal, float maxVal) { return (x - minVal) / (maxVal - minVal); } weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/snow/SnowEffect.kt +2 −53 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import android.graphics.Paint import android.graphics.RenderEffect import android.graphics.RuntimeShader import android.graphics.Shader import android.hardware.HardwareBuffer import android.util.SizeF import androidx.core.graphics.createBitmap import com.google.android.wallpaper.weathereffects.graphics.FrameBuffer Loading Loading @@ -68,14 +67,6 @@ class SnowEffect( private val accumulationFrameBufferPaint = Paint().also { it.shader = snowConfig.accumulatedSnowResultShader } private val snowFlakeSamplesBuffer = FrameBuffer( (SNOW_FLAKE_SAMPLES_COLUMN_COUNT * SNOW_FLAKE_SAMPLES_SIZE).toInt(), (SNOW_FLAKE_SAMPLES_ROW_COUNT * SNOW_FLAKE_SAMPLES_SIZE).toInt(), HardwareBuffer.RGB_888, ) private val snowFlakeSamplesPaint = Paint().also { it.shader = snowConfig.snowFlakeSamples } init { outlineFrameBuffer.setRenderEffect( RenderEffect.createBlurEffect( Loading @@ -84,7 +75,6 @@ class SnowEffect( Shader.TileMode.CLAMP, ) ) updateTextureUniforms() adjustCropping(surfaceSize) prepareColorGrading() Loading @@ -93,11 +83,11 @@ class SnowEffect( // Generate accumulated snow at the end after we updated all the uniforms. generateAccumulatedSnow() generateSnowFlakeSamples() } override fun update(deltaMillis: Long, frameTimeNanos: Long) { elapsedTime += snowSpeed * TimeUtils.millisToSeconds(deltaMillis) snowConfig.shader.setFloatUniform("time", elapsedTime) snowConfig.colorGradingShader.setInputShader("texture", snowConfig.shader) } Loading Loading @@ -200,8 +190,6 @@ class SnowEffect( "noise", BitmapShader(snowConfig.noiseTexture, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT), ) snowConfig.shader.setFloatUniform("snowFlakeSamplesSize", SNOW_FLAKE_SAMPLES_SIZE) snowConfig.snowFlakeSamples.setFloatUniform("snowFlakeSamplesSize", SNOW_FLAKE_SAMPLES_SIZE) } private fun prepareColorGrading() { Loading Loading @@ -270,36 +258,7 @@ class SnowEffect( override fun updateGridSize(newSurfaceSize: SizeF) { val gridSize = GraphicsUtils.computeDefaultGridSize(newSurfaceSize, snowConfig.pixelDensity) val gridSizeColumns = 7f * gridSize val gridSizeRows = 2f * gridSize snowConfig.shader.setFloatUniform("gridSize", gridSizeColumns, gridSizeRows) snowConfig.shader.setFloatUniform("cellAspectRatio", gridSizeColumns / gridSizeRows) } /** * Generates an offscreen bitmap containing pre-rendered snow flake patterns and properties. * * This bitmap serves as a lookup table for the main snow_effect shader, reducing per-frame * calculations. */ private fun generateSnowFlakeSamples() { val renderingCanvas = snowFlakeSamplesBuffer.beginDrawing() snowConfig.snowFlakeSamples.setFloatUniform( "canvasSize", SNOW_FLAKE_SAMPLES_COLUMN_COUNT * SNOW_FLAKE_SAMPLES_SIZE, SNOW_FLAKE_SAMPLES_ROW_COUNT * SNOW_FLAKE_SAMPLES_SIZE, ) renderingCanvas.drawPaint(snowFlakeSamplesPaint) snowFlakeSamplesBuffer.endDrawing() snowFlakeSamplesBuffer.tryObtainingImage( { snowFlakeSamples -> snowConfig.shader.setInputShader( "snowFlakeSamples", BitmapShader(snowFlakeSamples, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR), ) }, mainExecutor, ) snowConfig.shader.setFloatUniform("gridSize", 7 * gridSize, 2f * gridSize) } companion object { Loading @@ -313,15 +272,5 @@ class SnowEffect( // To prevent displaying outdated accumulation, we use a tiny blank bitmap to temporarily // clear the rendering area before the new texture is ready. private val blankBitmap = createBitmap(1, 1) // The `snow_flakes_samples` shader pre-generates diverse snow flake properties // (shape mask, intensity, etc.) in a bitmap, reducing per-frame calculations. A higher // column count provides more x-based visual variations. // The following values balance the visual benefits with memory and shader sampling costs. // Number of columns; increases x-based variation. const val SNOW_FLAKE_SAMPLES_COLUMN_COUNT = 14f const val SNOW_FLAKE_SAMPLES_ROW_COUNT = 4f // Side length of each flake's square bounding box. const val SNOW_FLAKE_SAMPLES_SIZE = 100f } } Loading
weathereffects/graphics/assets/shaders/snow.agsl +54 −21 Original line number Diff line number Diff line Loading @@ -19,12 +19,15 @@ struct Snow { highp vec2 cellUv; }; const vec2 snowFlakeShape = vec2(0.28, 0.26); // decreasedFactor should match minDescreasedFactor * 2, minDescreasedFactor is defined in snow_flake_samples.agsl const float decreasedFactor = 1.0 / 0.28; const mat2 rot45 = mat2( 0.7071067812, 0.7071067812, // First column. -0.7071067812, 0.7071067812 // second column. ); uniform half intensity; uniform half snowFlakeSamplesSize; const float farthestSnowLayerWiggleSpeed = 2.18; const float closestSnowLayerWiggleSpeed = 0.9; /** * Generates snow flakes. Loading @@ -50,14 +53,18 @@ Snow generateSnow( in float minLayerIndex, in float maxLayerIndex ) { // Normalize the layer index. 0 is closest, 1 is farthest. half normalizedLayerIndex = map(layerIndex, minLayerIndex, maxLayerIndex, 0, 1); /* Grid. */ // Increase the last number to make each layer more separate from the previous one. float depth = 0.65 + layerIndex * 0.755; float depth = 0.65 + layerIndex * 0.555; float speedAdj = 1. + layerIndex * 0.225; float layerR = idGenerator(layerIndex); snowGridSize *= depth; time += layerR * 58.3; // Number of rows and columns (each one is a cell, a drop). float cellAspectRatio = snowGridSize.x / snowGridSize.y; // Aspect ratio impacts visible cells. uv.y /= screenAspectRatio; // Skew uv.x so it goes to left or right Loading @@ -74,34 +81,60 @@ Snow generateSnow( // Have time affect the position of each column as well. gridUv.y += columnId * 2.6 + time * 0.19 * (1 - columnId); // Calclulate the grid this pixel belonging to, and also the offset in the cell. vec2 gridIdx = floor(gridUv); /* Cell. */ // Get the cell ID based on the grid position. Value from 0 to 1. float cellId = idGenerator(floor(gridUv)); // For each cell, we set the internal UV from -0.5 (left, bottom) to 0.5 (right, top). vec2 cellUv = fract(gridUv) - 0.5; cellUv.y *= -1.; // The bigger the decreasedFactor, the smaller the snow flake. vec2 snowFlakePos = vec2(cellUv.x, cellUv.y * (snowGridSize.x / snowGridSize.y - 1.0 / snowGridSize.y) + uv.y - 0.5 / screenAspectRatio) * decreasedFactor; if (abs(snowFlakePos.y) > 0.5 || abs(snowFlakePos.x) > 0.5 ) { return Snow(/* flakeMask= */ 0, cellUv); } vec4 color = snowFlakeSamples.eval(snowFlakeSamplesSize * (gridIdx - 0.5 + snowFlakePos)); float baseMask = color.r; half cellIntensity = color.g; float cellId = color.b; if (cellIntensity <= 1. - intensity) { // Remove snow flakes by seting flake mask to 0. /* * Disable snow flakes with some probabilty. This is done by 1) assigning a random intensity * value to the cell 2) then compare it with the given intensity. */ half cellIntensity = idGenerator(floor(vec2(cellId * 856.16, 272.2))); if (cellIntensity < 1. - intensity) { // Remove snow flakes by seeting flake mask to 0. return Snow(/* flakeMask= */ 0, cellUv); } /* Cell-id-based variations. */ // 0 = snow flake invisible, 1 = snow flake visible. float visibilityFactor = smoothstep( cellIntensity, max(cellIntensity - (0.02 + 0.18 * intensity), 0.0), 1 - intensity); // Adjust the size of each snow flake (higher is smaller) based on cell ID. float decreaseFactor = 2.0 + map(cellId, 0., 1., -0.1, 2.8) + 5. * (1 - visibilityFactor); // Adjust the opacity of the particle based on the cell id and distance from the camera. float farLayerFadeOut = map(normalizedLayerIndex, 0.7, 1, 1, 0.4); float closeLayerFadeOut = map(normalizedLayerIndex, 0, 0.2, 0.6, 1); float opacityVariation = (1. - 0.9 * cellId) * visibilityFactor * farLayerFadeOut * closeLayerFadeOut; float flakeMask = baseMask * opacityVariation; visibilityFactor * closeLayerFadeOut * farLayerFadeOut; /* Cell snow flake. */ // Calculate snow flake. vec2 snowFlakeShape = vec2(0.28, 0.26); vec2 snowFlakePos = vec2(cellUv.x, cellUv.y * cellAspectRatio); snowFlakePos -= vec2( 0., (uv.y - 0.5 / screenAspectRatio) - cellUv.y / snowGridSize.y ) * screenAspectRatio; snowFlakePos *= snowFlakeShape * decreaseFactor; vec2 snowFlakeShapeVariation = vec2(0.055) * // max variation vec2((cellId * 2. - 1.), // random A based on cell ID (fract((cellId + 0.03521) * 34.21) * 2. - 1.)); // random B based on cell ID vec2 snowFlakePosR = 1.016 * abs(rot45 * (snowFlakePos + snowFlakeShapeVariation)); snowFlakePos = abs(snowFlakePos); // Create the snowFlake mask. float flakeMask = smoothstep( 0.3, 0.200 - 0.3 * opacityVariation, snowFlakePos.x + snowFlakePos.y + snowFlakePosR.x + snowFlakePosR.y ) * opacityVariation; return Snow(flakeMask, cellUv); }
weathereffects/graphics/assets/shaders/snow_effect.agsl +2 −6 Original line number Diff line number Diff line Loading @@ -21,10 +21,8 @@ uniform float2 gridSize; uniform float time; uniform float screenAspectRatio; uniform float2 screenSize; uniform float cellAspectRatio; uniform mat3 transformMatrixBitmap; uniform mat3 transformMatrixWeather; uniform shader snowFlakeSamples; #include "shaders/constants.agsl" #include "shaders/utils.agsl" Loading @@ -32,13 +30,11 @@ uniform shader snowFlakeSamples; // Snow tint. const vec4 snowColor = vec4(1., 1., 1., 0.95); // Background tint const vec4 bgdTint = vec4(0.8, 0.8, 0.8, 0.07); // Indices of the different snow layers. const float farthestSnowLayerIndex = 4; const float farthestSnowLayerIndex = 6; const float midSnowLayerIndex = 2; const float closestSnowLayerIndex = 0; Loading
weathereffects/graphics/assets/shaders/snow_flake_samples.agsldeleted 100644 → 0 +0 −79 Original line number Diff line number Diff line /* * Copyright (C) 2025 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 float2 canvasSize; uniform float snowFlakeSamplesSize; #include "shaders/constants.agsl" #include "shaders/utils.agsl" const vec2 snowFlakeShape = vec2(0.28, 0.26); // Used in generate snow flake samples, and sampling it afterwards, to make sure snow flakes // will not go beyond bounding box const float minDecreaseFactor = 0.5 / 0.28; const float layerIndex = 0; const mat2 rot45 = mat2( 0.7071067812, 0.7071067812, // First column. -0.7071067812, 0.7071067812 // second column. ); /** * This shader generates snow flake samples per cell. It stores the flake mask in the red channel, * and pre-calculated `cellIntensity` and `cellId` in the green and blue channels for optimized access. */ vec4 main(float2 fragCoord) { // Calculate uv for snow based on transformed coordinates float2 uv = fragCoord / canvasSize; float layerR = idGenerator(layerIndex); // Number of rows and columns (each one is a cell, a snowflake). vec2 gridSize = floor(canvasSize / snowFlakeSamplesSize); float cellAspectRatio = gridSize.x / gridSize.y; // Aspect ratio impacts visible cells. vec2 gridUv = uv * gridSize; /* Cell. */ // Get the cell ID based on the grid position. Value from 0 to 1. float cellId = idGenerator(floor(gridUv)); // For each cell, we set the internal UV from -0.5 (left, bottom) to 0.5 (right, top). vec2 cellUv = fract(gridUv) - 0.5; cellUv.y *= -1.; /* * Disable snow flakes with some probabilty. This is done by 1) assigning a random intensity * value to the cell 2) then compare it with the given intensity. */ half cellIntensity = idGenerator(floor(vec2(cellId * 856.16, 272.2))); /* Cell snow flake. */ // Calculate snow flake. // With decreaseFactor <= minSnowShapeScale, we can make sure snow flakes not going out its // snowFlakeSamplesSize * snowFlakeSamplesSize bounding box float decreaseFactor = clamp(2.0 + map(cellId, 0., 1., 1., 1 + 5. * (1 - cellIntensity)), minDecreaseFactor, 4); // snowFlake center should be (0,0) in the cell when generating snowflake samples vec2 snowFlakePos = vec2(cellUv.x, cellUv.y); snowFlakePos *= snowFlakeShape * decreaseFactor; vec2 snowFlakeShapeVariation = vec2(0.055) * // max variation vec2((cellId * 2. - 1.), // random A based on cell ID (fract((cellId + 0.03521) * 34.21) * 2. - 1.)); // random B based on cell ID vec2 snowFlakePosR = 1.016 * abs(rot45 * (snowFlakePos + snowFlakeShapeVariation)); snowFlakePos = abs(snowFlakePos); // Create the snowFlake mask. float baseMask = 1 - clamp(snowFlakePos.x + snowFlakePos.y + snowFlakePosR.x + snowFlakePosR.y, 0, 1); return vec4(baseMask, cellIntensity, cellId , 1); }
weathereffects/graphics/assets/shaders/utils.agsl +0 −4 Original line number Diff line number Diff line Loading @@ -150,7 +150,3 @@ float2 transformPoint(mat3 transformMatrix, float2 point) { // Convert back to Cartesian coordinates (x, y) return transformedPoint.xy / transformedPoint.z; } float normalizeValue(float x, float minVal, float maxVal) { return (x - minVal) / (maxVal - minVal); }
weathereffects/graphics/src/main/java/com/google/android/wallpaper/weathereffects/graphics/snow/SnowEffect.kt +2 −53 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import android.graphics.Paint import android.graphics.RenderEffect import android.graphics.RuntimeShader import android.graphics.Shader import android.hardware.HardwareBuffer import android.util.SizeF import androidx.core.graphics.createBitmap import com.google.android.wallpaper.weathereffects.graphics.FrameBuffer Loading Loading @@ -68,14 +67,6 @@ class SnowEffect( private val accumulationFrameBufferPaint = Paint().also { it.shader = snowConfig.accumulatedSnowResultShader } private val snowFlakeSamplesBuffer = FrameBuffer( (SNOW_FLAKE_SAMPLES_COLUMN_COUNT * SNOW_FLAKE_SAMPLES_SIZE).toInt(), (SNOW_FLAKE_SAMPLES_ROW_COUNT * SNOW_FLAKE_SAMPLES_SIZE).toInt(), HardwareBuffer.RGB_888, ) private val snowFlakeSamplesPaint = Paint().also { it.shader = snowConfig.snowFlakeSamples } init { outlineFrameBuffer.setRenderEffect( RenderEffect.createBlurEffect( Loading @@ -84,7 +75,6 @@ class SnowEffect( Shader.TileMode.CLAMP, ) ) updateTextureUniforms() adjustCropping(surfaceSize) prepareColorGrading() Loading @@ -93,11 +83,11 @@ class SnowEffect( // Generate accumulated snow at the end after we updated all the uniforms. generateAccumulatedSnow() generateSnowFlakeSamples() } override fun update(deltaMillis: Long, frameTimeNanos: Long) { elapsedTime += snowSpeed * TimeUtils.millisToSeconds(deltaMillis) snowConfig.shader.setFloatUniform("time", elapsedTime) snowConfig.colorGradingShader.setInputShader("texture", snowConfig.shader) } Loading Loading @@ -200,8 +190,6 @@ class SnowEffect( "noise", BitmapShader(snowConfig.noiseTexture, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT), ) snowConfig.shader.setFloatUniform("snowFlakeSamplesSize", SNOW_FLAKE_SAMPLES_SIZE) snowConfig.snowFlakeSamples.setFloatUniform("snowFlakeSamplesSize", SNOW_FLAKE_SAMPLES_SIZE) } private fun prepareColorGrading() { Loading Loading @@ -270,36 +258,7 @@ class SnowEffect( override fun updateGridSize(newSurfaceSize: SizeF) { val gridSize = GraphicsUtils.computeDefaultGridSize(newSurfaceSize, snowConfig.pixelDensity) val gridSizeColumns = 7f * gridSize val gridSizeRows = 2f * gridSize snowConfig.shader.setFloatUniform("gridSize", gridSizeColumns, gridSizeRows) snowConfig.shader.setFloatUniform("cellAspectRatio", gridSizeColumns / gridSizeRows) } /** * Generates an offscreen bitmap containing pre-rendered snow flake patterns and properties. * * This bitmap serves as a lookup table for the main snow_effect shader, reducing per-frame * calculations. */ private fun generateSnowFlakeSamples() { val renderingCanvas = snowFlakeSamplesBuffer.beginDrawing() snowConfig.snowFlakeSamples.setFloatUniform( "canvasSize", SNOW_FLAKE_SAMPLES_COLUMN_COUNT * SNOW_FLAKE_SAMPLES_SIZE, SNOW_FLAKE_SAMPLES_ROW_COUNT * SNOW_FLAKE_SAMPLES_SIZE, ) renderingCanvas.drawPaint(snowFlakeSamplesPaint) snowFlakeSamplesBuffer.endDrawing() snowFlakeSamplesBuffer.tryObtainingImage( { snowFlakeSamples -> snowConfig.shader.setInputShader( "snowFlakeSamples", BitmapShader(snowFlakeSamples, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR), ) }, mainExecutor, ) snowConfig.shader.setFloatUniform("gridSize", 7 * gridSize, 2f * gridSize) } companion object { Loading @@ -313,15 +272,5 @@ class SnowEffect( // To prevent displaying outdated accumulation, we use a tiny blank bitmap to temporarily // clear the rendering area before the new texture is ready. private val blankBitmap = createBitmap(1, 1) // The `snow_flakes_samples` shader pre-generates diverse snow flake properties // (shape mask, intensity, etc.) in a bitmap, reducing per-frame calculations. A higher // column count provides more x-based visual variations. // The following values balance the visual benefits with memory and shader sampling costs. // Number of columns; increases x-based variation. const val SNOW_FLAKE_SAMPLES_COLUMN_COUNT = 14f const val SNOW_FLAKE_SAMPLES_ROW_COUNT = 4f // Side length of each flake's square bounding box. const val SNOW_FLAKE_SAMPLES_SIZE = 100f } }