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

Commit 027d58aa authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 11597038 from 9289a4d9 to 24Q3-release

Change-Id: Ib608429fc66232c1245d16868ae90a370cbf3dd7
parents 1de49c97 9289a4d9
Loading
Loading
Loading
Loading
+54 −17
Original line number Diff line number Diff line
@@ -26,6 +26,9 @@ const mat2 rot45 = mat2(

uniform half intensity;

const float farthestSnowLayerWiggleSpeed = 5.8;
const float closestSnowLayerWiggleSpeed = 2.6;

/**
 * Generates snow flakes.
 *
@@ -33,7 +36,10 @@ uniform half intensity;
 * @param screenAspectRatio the aspect ratio of the fragment where we will display the effect.
 * @param time the elapsed time.
 * @param snowGridSize the size of the grid, where each cell contains a snow flake.
 * @param layerNumber the layer of snow that we want to draw. Higher is farther from camera.
 * @param layerIndex the index of the current layer of snow that we want to draw. (Higher index
 *                      indicates that it's farther away from camera).
 * @param minLayerIndex the index of the minimum layer.
 * @param maxLayerIndex the index of the maximum layers.
 *
 * @returns Snow with the snow info.
 */
@@ -43,13 +49,18 @@ Snow generateSnow(
    in float screenAspectRatio,
    in float time,
    in vec2 snowGridSize,
    in float layerNumber
    in float layerIndex,
    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 = 1. + layerNumber * 0.35;
    float speedAdj = 1. + layerNumber * 0.15;
    float layerR = idGenerator(layerNumber);
    float depth = 0.65 + layerIndex * 0.41;
    float speedAdj = 1. + layerIndex * 0.15;
    float layerR = idGenerator(layerIndex);
    snowGridSize *= depth;
    time += layerR * 58.3;
    // Number of rows and columns (each one is a cell, a drop).
@@ -67,7 +78,8 @@ Snow generateSnow(
    gridUv.y += verticalGridPos;
    // Generate column id, to offset columns vertically (so snow flakes are not aligned).
    float columnId = idGenerator(floor(gridUv.x));
    gridUv.y += columnId * 2.6;
    // Have time affect the position of each column as well.
    gridUv.y += columnId * 2.6 + time * 0.09 * (1 - columnId);

    /* Cell. */
    // Get the cell ID based on the grid position. Value from 0 to 1.
@@ -87,21 +99,43 @@ Snow generateSnow(
    }

    /* Cell-id-based variations. */
    // Adjust time based on columnId.
    // Adjusts scale of each snow flake (higher is smaller).
    float scaleVariation = 2.0 + 2.7 * cellId;
    float opacityVariation = (1. - 0.9 * cellId);
    // 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 *
        closeLayerFadeOut *
        farLayerFadeOut;

    /* Cell snow flake. */

    // Horizontal movement: Wiggle.
    float wiggleSpeed = 3.0;
    // 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.4 + 0.4 * smoothstep(0.5, 2.5, layerNumber);
    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(uv.y + cellId * 2.1, wiggleSpeed * speedAdj);
    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).
@@ -114,8 +148,11 @@ Snow generateSnow(
    vec2 snowFlakeShape = vec2(1., 1.2);
    vec2 snowFlakePos = vec2(snowFlakePosUncorrected / cellAspectRatio, cellUv.y);
    snowFlakePos -= vec2(0., uv.y - 0.5) * cellId;
    snowFlakePos *= snowFlakeShape * scaleVariation;
    vec2 snowFlakePosR = 1.016 * abs(rot45 * (snowFlakePos + (cellId * 2. - 1.) * vec2(0.050)));
    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(
+71 −45
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
uniform shader foreground;
uniform shader background;
uniform shader accumulatedSnow;
uniform shader noise;
uniform float2 uvOffsetFgd;
uniform float2 uvScaleFgd;
uniform float2 uvOffsetBgd;
@@ -29,71 +30,96 @@ uniform float2 screenSize;
#include "shaders/utils.agsl"
#include "shaders/snow.agsl"

/* Constants that can be modified. */
// Snow tint.
const vec3 snowColor = vec3(0.9);
// Glass tint.
const vec3 glassTint = vec3(0.8); // gray
const vec4 snowColor = vec4(1., 1., 1., 0.95);
// Background tint
const vec4 bgdTint = vec4(0.8, 0.8, 0.8, 0.07);

// snow opacity (how visible it is).
const float snowOpacity = 1.4;

// how frosted the glass is.
const float frostedGlassIntensity = 0.07;
// Indices of the different snow layers.
const float farthestSnowLayerIndex = 9;
const float midSnowLayerIndex = 3;
const float closestSnowLayerIndex = 0;

vec4 main(float2 fragCoord) {
    float2 uv = fragCoord / screenSize;
    float2 uvAdjusted = vec2(uv.x, uv.y / screenAspectRatio);

    /**
     * The effect is consisted of 2 image textures (foreground and background) + 10 layers of
     * snow + 1 layer of snow accumulation. Below describes the rendering order (back to front):
     * 1. Background
     * 2. Background snow layers (from farthest layer to mid layer)
     * 3. Foreground
     * 4. Snow accumulation layer (on subject)
     * 5. Foreground snow layers (from mid layer to closest layer)
     */

    // Adjusts the UVs to have the expected rect of the image.
    float2 adjustedUvForeground = fragCoord * uvScaleFgd + uvOffsetFgd;
    vec4 colorForeground = foreground.eval(adjustedUvForeground);
    vec4 colorBackground = background.eval(fragCoord * uvScaleBgd + uvOffsetBgd);

    vec4 color = vec4(0., 0., 0., 1.);
    // 1. Draw background.
    vec4 color = colorBackground;

    // Add some slight tint to the frosted glass.
    // Add slight tint to the background.
    color.rgb = normalBlendNotPremultiplied(color.rgb, bgdTint.rgb, bgdTint.a);

    // Get color of the background texture.
    color.rgb = mix(colorBackground.rgb, glassTint, frostedGlassIntensity);
    for (half i = 9.; i > 2.; i--) {
        // Generate snow behind the subject.
        // Normalized layer index.
        half idx = (i - 2.) / (9. - 2.);
    // 2. Generate snow layers behind the subject.
    for (float i = farthestSnowLayerIndex; i > midSnowLayerIndex; i--) {
        Snow snow = generateSnow(
            uv,
            screenAspectRatio,
              time * mix(1.25, 5., idx),
              /* Grid size = */ vec2(mix(3.0, 6.0, idx), mix(1.0, 3.0, idx)),
              /* layer number = */ i);

        color.rgb = mix(color.rgb, snowColor, snowOpacity * snow.flakeMask);
            time,
            // TODO: adjust grid size based on aspect ratio.
            /* Grid size = */ vec2(7., 1.5),
            /* layer number = */ i,
            closestSnowLayerIndex,
            farthestSnowLayerIndex);

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

    // Add the foreground. Any effect from here will be in front of the subject.
    // 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);

    // Add accumulated snow.
    vec2 accSnow = accumulatedSnow.eval(adjustedUvForeground).rg;
    float snowLayer = smoothstep(0.2, 0.8, accSnow.r);
    float snowTexture = smoothstep(0.2, 0.7, accSnow.g);
    color.rgb = mix(color.rgb, vec3(0.95), 0.98 * snowLayer * (0.05 + 0.95 * snowTexture));
    // 4. Add accumulated snow layer.
    // Load noise texture to give "fluffy-ness" to the snow. Displace the sampling of the noise.
    vec3 cloudsNoise = noise.eval(uvAdjusted * 7000 + vec2(fragCoord.y, -fragCoord.x)).rgb;
    // Add dither to give texture to the snow and ruffle the edges.
    float dither = abs(triangleNoise(fragCoord * 0.01));

    for (half i = 2.; i >= 0.; i--) {
        // Generate snow behind the subject.
    // Get the accumulated snow buffer. r contains its mask, g contains some random noise.
    vec2 accSnow = accumulatedSnow.eval(adjustedUvForeground).rg;
    // Sharpen the mask of the accumulated snow, but not in excess.
    float accSnowMask = smoothstep(0.1, 0.9, /* mask= */ accSnow.r);
    // 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.
    float accSnowTexture = smoothstep(0.2, 0.7, /* noise= */ accSnow.g) * 0.7;
    accSnowTexture = map(accSnowTexture, dither - 1, 1, 0, 1);
    // Adjust snow texture coverage/shape.
    accSnowTexture = map(accSnowTexture, 0.67, 0.8, 0, 1);
    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--) {
        Snow snow = generateSnow(
            uv,
            screenAspectRatio,
              time * 1.25,
              /* Grid size = */ vec2(i + 1., 1.4),
              /* layer number = */ i);

        color.rgb = mix(color.rgb, snowColor, snowOpacity * snow.flakeMask);
            time,
            // TODO: adjust grid size based on aspect ratio
            /* Grid size = */ vec2(7., 1.5),
            /* layer number = */ i,
            closestSnowLayerIndex,
            farthestSnowLayerIndex);

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

    /* Debug snow */
    // resets color.
    // color.rgb *= 0.;
    // color.rgb += snow.flakeMask;
    // if (snow.cellUv.x > 0.49 || snow.cellUv.y > 0.49) color.r = 1.0;

    return color;
}
+14 −0
Original line number Diff line number Diff line
@@ -94,6 +94,20 @@ vec3 normalBlendWithWhiteSrc(vec3 b, float o) {
    return b * (1. - o) + o;
}

/*
 * This is the normal blend mode in which the foreground is painted on top of the background based
 * on the foreground opacity.
 *
 * @param b the background color.
 * @param f the foreground color.
 * @param o the mask or the foreground alpha.
 *
 * Note: this blending function expects the foreground to NOT have premultiplied alpha.
 */
vec3 normalBlendNotPremultiplied(vec3 b, vec3 f, float o) {
    return mix(b, f, o);
}

/** Math Utils */
// function created on Grapher (equation decided by testing in Grapher).
float wiggle(float time, float wiggleSpeed) {
+5 −0
Original line number Diff line number Diff line
@@ -153,6 +153,11 @@ class SnowEffect(
            "background",
            BitmapShader(snowConfig.background, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR)
        )

        snowConfig.shader.setInputBuffer(
            "noise",
            BitmapShader(snowConfig.noiseTexture, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)
        )
    }

    private fun prepareColorGrading() {
+8 −0
Original line number Diff line number Diff line
@@ -30,6 +30,11 @@ data class SnowEffectConfig(
    val accumulatedSnowShader: RuntimeShader,
    /** The color grading shader. */
    val colorGradingShader: RuntimeShader,
    /**
     * The noise texture, which will be used to add fluffiness to the snow flakes. The texture is
     * expected to be tileable, and at least 16-bit per channel for render quality.
     */
    val noiseTexture: Bitmap,
    /** The main lut (color grading) for the effect. */
    val lut: Bitmap?,
    /** A bitmap containing the foreground of the image. */
@@ -64,6 +69,8 @@ data class SnowEffectConfig(
        accumulatedSnowShader =
            GraphicsUtils.loadShader(context.assets, ACCUMULATED_SNOW_SHADER_PATH),
        colorGradingShader = GraphicsUtils.loadShader(context.assets, COLOR_GRADING_SHADER_PATH),
        noiseTexture = GraphicsUtils.loadTexture(context.assets, NOISE_TEXTURE_PATH)
                ?: throw RuntimeException("Noise texture is missing."),
        lut = GraphicsUtils.loadTexture(context.assets, LOOKUP_TABLE_TEXTURE_PATH),
        foreground,
        background,
@@ -77,6 +84,7 @@ data class SnowEffectConfig(
        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/lut_rain_and_fog.png"
        private const val BLUR_RADIUS = 20f
        private const val DEFAULT_INTENSITY = 1f