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

Commit 45abd578 authored by Yein Jo's avatar Yein Jo Committed by Android (Google) Code Review
Browse files

Merge changes I8bea0b0a,Id7ebe430,I0194d91e,I782e86c6 into main

* changes:
  Last sync for the rain effect.
  Add noise to the rain droplets on the glass surface.
  Add static rain droplets on the glass surface.
  Add rain splash.
parents 2176df2e f7be7854
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -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);
}
+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.);
}
+12 −4
Original line number Diff line number Diff line
@@ -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.
@@ -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;
@@ -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,
+50 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

uniform shader foreground;
uniform shader background;
uniform shader outlineBuffer;
uniform float2 uvOffsetFgd;
uniform float2 uvScaleFgd;
uniform float2 uvOffsetBgd;
@@ -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;

@@ -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,
+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