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

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

Merge "optimize snow effects" into main

parents c32cb42c e2f828a6
Loading
Loading
Loading
Loading
+3 −31
Original line number Diff line number Diff line
@@ -58,8 +58,8 @@ Snow generateSnow(

    /* Grid. */
    // Increase the last number to make each layer more separate from the previous one.
    float depth = 0.65 + layerIndex * 0.37;
    float speedAdj = 1. + layerIndex * 0.15;
    float depth = 0.65 + layerIndex * 0.555;
    float speedAdj = 1. + layerIndex * 0.225;
    float layerR = idGenerator(layerIndex);
    snowGridSize *= depth;
    time += layerR * 58.3;
@@ -116,37 +116,9 @@ Snow generateSnow(
        farLayerFadeOut;

    /* Cell snow flake. */
    // Horizontal movement: Wiggle (Adjust the wiggle speed based on the distance).
    float wiggleSpeed = map(
        normalizedLayerIndex,
        0.2,
        0.7,
        closestSnowLayerWiggleSpeed,
        farthestSnowLayerWiggleSpeed);
    // Adjust wiggle based on layer number (0 = closer to screen => we want less movement).
    float wiggleAmp = 0.6 + 0.4 * smoothstep(0.5, 2.5, layerIndex);
    // Define the start based on the cell id.
    float horizontalStartAmp = 0.5;
    // Add the wiggle (equation decided by testing in Grapher).
    float horizontalWiggle = wiggle(
        // Current uv position.
        uv.y
        // Adjustment so the shape is not skewed.
        - cellUv.y / snowGridSize.y
        // variation based on cell ID.
        + cellId * 2.1,
        wiggleSpeed * speedAdj);

    // Add the start and wiggle and make that when we are closer to the edge, we don't wiggle much
    // (so the drop doesn't go outside it's cell).
    horizontalWiggle = horizontalStartAmp * wiggleAmp * horizontalWiggle;

    // Calculate main cell drop.
    float snowFlakePosUncorrected = (cellUv.x - horizontalWiggle);

    // Calculate snow flake.
    vec2 snowFlakeShape = vec2(0.28, 0.26);
    vec2 snowFlakePos = vec2(snowFlakePosUncorrected, cellUv.y * cellAspectRatio);
    vec2 snowFlakePos = vec2(cellUv.x, cellUv.y * cellAspectRatio);
    snowFlakePos -= vec2(
            0.,
            (uv.y - 0.5 / screenAspectRatio)  - cellUv.y / snowGridSize.y
+1 −3
Original line number Diff line number Diff line
@@ -37,10 +37,8 @@ vec4 main(float2 fragCoord) {
    float dY = (aN - aS) * 0.5;
    dY = max(dY, 0.0);

    float accumulatedSnow = smoothstep(0.1, 1.8, dY * 5.0);
    vec4 color = vec4(0., 0., 0., 1.);
    color.r = accumulatedSnow;
    color.r = dY * 10.0;
    color.g = random(uv);
    color.b = variation;
    return color;
}
+29 −26
Original line number Diff line number Diff line
@@ -35,8 +35,8 @@ const vec4 snowColor = vec4(1., 1., 1., 0.95);
const vec4 bgdTint = vec4(0.8, 0.8, 0.8, 0.07);

// Indices of the different snow layers.
const float farthestSnowLayerIndex = 9;
const float midSnowLayerIndex = 3;
const float farthestSnowLayerIndex = 6;
const float midSnowLayerIndex = 2;
const float closestSnowLayerIndex = 0;

vec4 main(float2 fragCoord) {
@@ -52,7 +52,6 @@ vec4 main(float2 fragCoord) {

    // Apply transform matrix to fragCoord
    float2 adjustedUv = transformPoint(transformMatrixBitmap, fragCoord);

    // Calculate uv for snow based on transformed coordinates
    float2 uv = transformPoint(transformMatrixWeather, fragCoord) / screenSize;
    float2 uvAdjusted = vec2(uv.x, uv.y / screenAspectRatio);
@@ -74,6 +73,7 @@ vec4 main(float2 fragCoord) {
    color.rgb = normalBlendNotPremultiplied(color.rgb, bgdTint.rgb, bgdTint.a);

    // 2. Generate snow layers behind the subject.
    if (colorForeground.a == 0) {
        for (float i = farthestSnowLayerIndex; i > midSnowLayerIndex; i--) {
            Snow snow = generateSnow(
                uv,
@@ -87,6 +87,7 @@ vec4 main(float2 fragCoord) {
            color.rgb =
                normalBlendNotPremultiplied(color.rgb, snowColor.rgb, snowColor.a * snow.flakeMask);
        }
    }

    // 3. Add the foreground layer. Any effect from here will be in front of the subject.
    color.rgb = normalBlend(color.rgb, colorForeground.rgb, colorForeground.a);
@@ -100,7 +101,8 @@ vec4 main(float2 fragCoord) {
    // Get the accumulated snow buffer. r contains its mask, g contains some random noise.
    vec2 accSnow = accumulatedSnow.eval(adjustedUv).rg;
    // Sharpen the mask of the accumulated snow, but not in excess.
    float accSnowMask = smoothstep(0.1, 0.9, /* mask= */ accSnow.r);
    float accSnowMask = smoothstep( (1.-intensity), 1.0, /* mask= */accSnow.r);
    if (accSnowMask > 0) {
        // Makes the edges of the snow layer accumulation rougher.
        accSnowMask = map(accSnowMask, 1. - cloudsNoise.b - 0.3 * dither, 1., 0., 1.);
        // Load snow texture and dither. Make it have gray-ish values.
@@ -111,6 +113,7 @@ vec4 main(float2 fragCoord) {
        accSnowMask = map(accSnowMask, 0., 1., 0., 1.- 0.6 * accSnowTexture - 0.35 * dither);

        color.rgb = normalBlendNotPremultiplied(color.rgb, snowColor.rgb, snowColor.a * accSnowMask);
    }

    // 5. Generate snow in front of the subject.
    for (float i = midSnowLayerIndex; i >= closestSnowLayerIndex; i--) {
+43 −16
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import com.google.android.wallpaper.weathereffects.graphics.WeatherEffect.Compan
import com.google.android.wallpaper.weathereffects.graphics.WeatherEffectBase
import com.google.android.wallpaper.weathereffects.graphics.utils.GraphicsUtils
import com.google.android.wallpaper.weathereffects.graphics.utils.MathUtils
import com.google.android.wallpaper.weathereffects.graphics.utils.MatrixUtils.getScale
import com.google.android.wallpaper.weathereffects.graphics.utils.TimeUtils
import java.util.concurrent.Executor

@@ -54,7 +55,11 @@ class SnowEffect(

    init {
        frameBuffer.setRenderEffect(
            RenderEffect.createBlurEffect(4f / bitmapScale, 4f / bitmapScale, Shader.TileMode.CLAMP)
            RenderEffect.createBlurEffect(
                BLUR_RADIUS / bitmapScale,
                BLUR_RADIUS / bitmapScale,
                Shader.TileMode.CLAMP,
            )
        )
        updateTextureUniforms()
        adjustCropping(surfaceSize)
@@ -88,23 +93,26 @@ class SnowEffect(
         * Increase effect speed as weather intensity decreases. This compensates for the floaty
         * appearance when there are fewer particles at the original speed.
         */
        if (this.intensity != intensity) {
            snowSpeed = MathUtils.map(intensity, 0f, 1f, 2.5f, 1.7f)
            this.intensity = intensity
        // Regenerate accumulated snow since the uniform changed.
        generateAccumulatedSnow()
        }
    }

    override fun setBitmaps(foreground: Bitmap?, background: Bitmap): Boolean {
        if (!super.setBitmaps(foreground, background)) {
            return false
        }

        frameBuffer.close()
        frameBuffer =
            FrameBuffer(background.width, background.height).apply {
                setRenderEffect(
        frameBuffer = FrameBuffer(background.width, background.height)
        val newScale = getScale(parallaxMatrix)
        if (bitmapScale != newScale) {
            bitmapScale = newScale
            frameBuffer.setRenderEffect(
                RenderEffect.createBlurEffect(
                        4f / bitmapScale,
                        4f / bitmapScale,
                    BLUR_RADIUS / bitmapScale,
                    BLUR_RADIUS / bitmapScale,
                    Shader.TileMode.CLAMP,
                )
            )
@@ -128,9 +136,19 @@ class SnowEffect(
        get() = snowConfig.colorGradingIntensity

    override fun setMatrix(matrix: Matrix) {
        val oldScale = bitmapScale
        super.setMatrix(matrix)
        if (bitmapScale != oldScale) {
            frameBuffer.setRenderEffect(
                RenderEffect.createBlurEffect(
                    BLUR_RADIUS / bitmapScale,
                    BLUR_RADIUS / bitmapScale,
                    Shader.TileMode.CLAMP,
                )
            )
            generateAccumulatedSnow()
        }
    }

    override fun updateTextureUniforms() {
        super.updateTextureUniforms()
@@ -155,13 +173,14 @@ class SnowEffect(
        snowConfig.accumulatedSnowShader.setFloatUniform("scale", bitmapScale)
        snowConfig.accumulatedSnowShader.setFloatUniform(
            "snowThickness",
            snowConfig.maxAccumulatedSnowThickness * intensity / bitmapScale,
            SNOW_THICKNESS / bitmapScale,
        )
        snowConfig.accumulatedSnowShader.setFloatUniform("screenWidth", surfaceSize.width)
        snowConfig.accumulatedSnowShader.setInputBuffer(
            "foreground",
            BitmapShader(foreground, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR),
        )

        renderingCanvas.drawPaint(frameBufferPaint)
        frameBuffer.endDrawing()

@@ -180,4 +199,12 @@ class SnowEffect(
        val gridSize = GraphicsUtils.computeDefaultGridSize(newSurfaceSize, snowConfig.pixelDensity)
        snowConfig.shader.setFloatUniform("gridSize", 7 * gridSize, 2f * gridSize)
    }

    companion object {
        val BLUR_RADIUS = 4f
        // Use blur effect for both blurring the snow accumulation and generating a gradient edge
        // so that intensity can control snow thickness by cut the gradient edge in snow_effect
        // shader.
        val SNOW_THICKNESS = 6f
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -64,16 +64,16 @@ data class SnowEffectConfig(
        lut = GraphicsUtils.loadTexture(assets, LOOKUP_TABLE_TEXTURE_PATH),
        pixelDensity,
        COLOR_GRADING_INTENSITY,
        MAX_SNOW_THICKNESS
        MAX_SNOW_THICKNESS,
    )

    private companion object {
    companion object {
        private const val SHADER_PATH = "shaders/snow_effect.agsl"
        private const val ACCUMULATED_SNOW_SHADER_PATH = "shaders/snow_accumulation.agsl"
        private const val COLOR_GRADING_SHADER_PATH = "shaders/color_grading_lut.agsl"
        private const val NOISE_TEXTURE_PATH = "textures/clouds.png"
        private const val LOOKUP_TABLE_TEXTURE_PATH = "textures/snow_lut.png"
        private const val COLOR_GRADING_INTENSITY = 0.25f
        private const val MAX_SNOW_THICKNESS = 10f
        const val MAX_SNOW_THICKNESS = 10f
    }
}