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

Commit e1351b6b authored by Yein Jo's avatar Yein Jo
Browse files

Optimize fog effect.

Reduced the computational cost roughly by 6 times.
Please refer to the design doc linked to the bug.

Bug: 303502646
Test: Perfetto & intermediate compiled shader & HWUI debugging
Change-Id: I482471ce0fd6e78544b6d758df11b50cbfd05cc1
parent b4e8115b
Loading
Loading
Loading
Loading
+9 −9
Original line number Diff line number Diff line
@@ -20,26 +20,26 @@ uniform float2 uvOffsetFgd;
uniform float2 uvScaleFgd;
uniform float2 uvOffsetBgd;
uniform float2 uvScaleBgd;
uniform half2 timeForeground;
uniform half2 timeBackground;
uniform half timeForeground;
uniform half timeBackground;
uniform half screenAspectRatio;
uniform half2 screenSize;
uniform half pixelDensity;

#include "shaders/constants.agsl"
#include "shaders/utils.agsl"
#include "shaders/simplex_noise.agsl"
#include "shaders/simplex_flow_noise.agsl"

// TODO: explore a more performant way of generating the volumetric fog effect.
const int numOctaves = 2;

float fbm (vec3 st, vec2 time) {
    vec3 p = st;
float fbm(vec2 p, half time) {
    float a = 0.5;
    float result = 0.0;
    float rot = 1.2;

    for (int i = 0; i < numOctaves; i++) {
        result += a * simplex3d(vec3(p.xy + time, p.z));
        result += a * simplex2d_flow(p, rot, time);
        rot *= 1.25;
        p *= 2.0152;
        a *= 0.5;
    }
@@ -54,8 +54,8 @@ vec4 main(float2 fragCoord) {
    vec4 colorForeground = foreground.eval(fragCoord * uvScaleFgd + uvOffsetFgd);
    vec4 color = background.eval(fragCoord * uvScaleBgd + uvOffsetBgd);

    float frontFog = smoothstep(-0.616, 0.552, fbm(vec3(uv * 0.886, 123.1), timeForeground));
    float bgdFog = smoothstep(-0.744, 0.28, fbm(vec3(uv * 1.2, 231.), timeBackground));
    float frontFog = smoothstep(-0.616, 0.552, fbm(uv * 0.8, timeForeground));
    float bgdFog = smoothstep(-0.744, 0.28, fbm(uv * 1.2, timeBackground));

    float dither = 1. - triangleNoise(fragCoord * pixelDensity) * 0.161;

+80 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.
 */

const float SKEW = 0.366025404; // (sqrt(3)-1)/2
const float UNSKEW = 0.211324865; // (3-sqrt(3))/6

half2 hash2d(vec2 p) {
    p = vec2(dot(p,vec2(157.1, 235.7)), dot(p,vec2(573.5, 13.3)));
    return fract(sin(p) * 877.343) * 2. -1.; // [-1, 1]
}

half hash1d(vec2 p) {
    return fract(sin(dot(p, vec2(343.0, 49.0)))) * 2. -1.; // [-1, 1]
}

vec2 getVectorFromAngle(float theta) {
    return vec2(cos(theta), sin(theta));
}

// 2D Simplex noise with dynamic gradient vectors. Return value [-1, 1].
//
// This method produces similar visuals to Simplex noise 3D, but at a lower computational cost.
// The snapshot of the noise is the same as a regular Simplex noise. However, when animated, it
// creates a swirling motion that is more suitable for flow-y effects.
//
// The difference in motion is not noticeable unless the following conditions are met:
// 1) The rotation offset is identical for all vertex gradients.
// 2) The noise is moving quickly.
// 3) The noise is tiled.
//
// This method is recommended for use because it is significantly more performant than 3D Simplex
// noise. It is especially useful for simulating fire, clouds, and fog, which all have advection.
//
// rot is an angle in radian that you want to step for each dt.
float simplex2d_flow(vec2 p, float rot, float time) {
    // Skew the input coordinate and find the simplex index.
    vec2 i = floor(p + (p.x + p.y) * SKEW);
    // First vertex of the triangle.
    vec2 v0 = p - i + (i.x + i.y) * UNSKEW;

    // Find two other vertices.
    // Determines which triangle we should walk.
    // If y>x, m=0 upper triangle, x>y, m=1 lower triangle.
    float side = step(v0.y, v0.x);
    vec2 walk = vec2(side, 1.0 - side);

    vec2 v1 = v0 - walk + UNSKEW;
    vec2 v2 = v0 - 1.0 + 2.*UNSKEW;

    // Get random gradient vector.
    vec2 g0 = hash2d(i);
    vec2 g1 = hash2d(i+walk);
    vec2 g2 = hash2d(i+1.0);

    // Make the gradient vectors dynamic by adding rotations.
    g0 += getVectorFromAngle(rot * time * hash1d(i));
    g1 += getVectorFromAngle(rot * time * hash1d(i+walk));
    g2 += getVectorFromAngle(rot * time * hash1d(i+1.));

    // Kernel summation
    vec3 w = max(0.5 - vec3(dot(v0, v0), dot(v1, v1), dot(v2, v2)), 0.0);

    w = w*w*w*w;
    vec3 n = w * vec3(dot(v0, g0), dot(v1, g1), dot(v2, g2));

    return dot(n, vec3(32.0));
}
+5 −18
Original line number Diff line number Diff line
@@ -35,10 +35,6 @@ class FogEffect(
) : WeatherEffect {

    private val fogPaint = Paint().also { it.shader = fogConfig.colorGradingShader }
    private val variationFgd: FloatArray = FloatArray(2)
    private val timeFgd: FloatArray = FloatArray(2)
    private val variationBgd: FloatArray = FloatArray(2)
    private val timeBgd: FloatArray = FloatArray(2)
    private var elapsedTime: Float = 0f

    init {
@@ -51,23 +47,14 @@ class FogEffect(

    override fun update(deltaMillis: Long, frameTimeNanos: Long) {
        val time = 0.02f * frameTimeNanos.toFloat() * NANOS_TO_SECONDS
        val variation = sin(time + sin(3f * time)) * 0.5f + 0.5f
        elapsedTime += variation * deltaMillis * MILLIS_TO_SECONDS

        val speed = elapsedTime * 0.248f

        variationFgd[0] = 0.256f * sin(speed)
        variationFgd[1] = 0.156f * sin(speed) * sin(speed)
        timeFgd[0] = 0.04f * elapsedTime * 5f + variationFgd[0]
        timeFgd[1] = 0.003f * elapsedTime * 5f + variationFgd[1]
        // Variation range [1, 1.5]. We don't want the variation to be 0.
        val variation = (sin(time + sin(3f * time)) * 0.5f + 0.5f) * 1.5f
        elapsedTime += variation * deltaMillis * MILLIS_TO_SECONDS

        variationBgd[0] = 0.156f * sin((speed + Math.PI.toFloat() / 2.0f))
        variationBgd[1] = 0.0156f * sin((speed * Math.PI.toFloat() / 3.0f)) * sin(speed)
        timeBgd[0] = 0.08f * elapsedTime * 5f + variationBgd[0]
        timeBgd[1] = 0.02f * elapsedTime * 5f + variationBgd[1]
        fogConfig.shader.setFloatUniform("timeBackground", elapsedTime * 1.5f)
        fogConfig.shader.setFloatUniform("timeForeground", elapsedTime * 2.0f)

        fogConfig.shader.setFloatUniform("timeForeground", timeFgd[0], timeFgd[1])
        fogConfig.shader.setFloatUniform("timeBackground", timeBgd[0], timeBgd[1])
        fogConfig.colorGradingShader.setInputShader("texture", fogConfig.shader)
    }