Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 345dac54 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Revert "Cache snow flakes and reduce snow layers"" into main

parents 4876737b 5903a73c
Loading
Loading
Loading
Loading
+54 −21
Original line number Diff line number Diff line
@@ -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.
@@ -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
@@ -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);
}
+2 −6
Original line number Diff line number Diff line
@@ -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"
@@ -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;

+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);
}
+0 −4
Original line number Diff line number Diff line
@@ -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);
}
+2 −53
Original line number Diff line number Diff line
@@ -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
@@ -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(
@@ -84,7 +75,6 @@ class SnowEffect(
                Shader.TileMode.CLAMP,
            )
        )

        updateTextureUniforms()
        adjustCropping(surfaceSize)
        prepareColorGrading()
@@ -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)
    }
@@ -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() {
@@ -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 {
@@ -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