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

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

Merge "Optimize fog effect." into main

parents a3ebb332 e1351b6b
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)
    }