Merge "Add fractal noise support in TurbulenceNoiseShader" into udc-dev

This commit is contained in:
Yein Jo
2023-03-13 21:14:14 +00:00
committed by Android (Google) Code Review
3 changed files with 99 additions and 22 deletions

View File

@@ -53,6 +53,19 @@ class ShaderUtilLibrary {
cos(p.y * 0.01 + time * 0.005931)) * distort_amount_xy;
}
// Perceived luminosity (L′), not absolute luminosity.
half getLuminosity(vec3 c) {
return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;
}
// Creates a luminosity mask and clamp to the legal range.
vec3 maskLuminosity(vec3 dest, float lum) {
dest.rgb *= vec3(lum);
// Clip back into the legal range
dest = clamp(dest, vec3(0.), vec3(1.0));
return dest;
}
// Return range [-1, 1].
vec3 hash(vec3 p) {
p = fract(p * vec3(.3456, .1234, .9876));
@@ -62,14 +75,14 @@ class ShaderUtilLibrary {
}
// Skew factors (non-uniform).
const float SKEW = 0.3333333; // 1/3
const float UNSKEW = 0.1666667; // 1/6
const half SKEW = 0.3333333; // 1/3
const half UNSKEW = 0.1666667; // 1/6
// Return range roughly [-1,1].
// It's because the hash function (that returns a random gradient vector) returns
// different magnitude of vectors. Noise doesn't have to be in the precise range thus
// skipped normalize.
float simplex3d(vec3 p) {
half simplex3d(vec3 p) {
// Skew the input coordinate, so that we get squashed cubical grid
vec3 s = floor(p + (p.x + p.y + p.z) * SKEW);
@@ -143,6 +156,22 @@ class ShaderUtilLibrary {
// Should multiply by the possible max contribution to adjust the range in [-1,1].
return dot(vec4(32.), nc);
}
// Random rotations.
// The way you create fractal noise is layering simplex noise with some rotation.
// To make random cloud looking noise, the rotations should not align. (Otherwise it
// creates patterned noise).
// Below rotations only rotate in one axis.
const mat3 rot1 = mat3(1.0, 0. ,0., 0., 0.15, -0.98, 0., 0.98, 0.15);
const mat3 rot2 = mat3(-0.95, 0. ,-0.3, 0., 1., 0., 0.3, 0., -0.95);
const mat3 rot3 = mat3(1.0, 0. ,0., 0., -0.44, -0.89, 0., 0.89, -0.44);
// Octave = 4
// Divide each coefficient by 3 to produce more grainy noise.
half simplex3d_fractal(vec3 mat) {
return 0.675 * simplex3d(mat * rot1) + 0.225 * simplex3d(2.0 * mat * rot2)
+ 0.075 * simplex3d(4.0 * mat * rot3) + 0.025 * simplex3d(8.0 * mat);
}
"""
}
}

View File

@@ -19,8 +19,13 @@ import android.graphics.RuntimeShader
import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary
import java.lang.Float.max
/** Shader that renders turbulence simplex noise, with no octave. */
class TurbulenceNoiseShader : RuntimeShader(TURBULENCE_NOISE_SHADER) {
/**
* Shader that renders turbulence simplex noise, by default no octave.
*
* @param useFractal whether to use fractal noise (4 octaves).
*/
class TurbulenceNoiseShader(useFractal: Boolean = false) :
RuntimeShader(if (useFractal) FRACTAL_NOISE_SHADER else SIMPLEX_NOISE_SHADER) {
// language=AGSL
companion object {
private const val UNIFORMS =
@@ -35,21 +40,7 @@ class TurbulenceNoiseShader : RuntimeShader(TURBULENCE_NOISE_SHADER) {
layout(color) uniform vec4 in_backgroundColor;
"""
private const val SHADER_LIB =
"""
float getLuminosity(vec3 c) {
return 0.3*c.r + 0.59*c.g + 0.11*c.b;
}
vec3 maskLuminosity(vec3 dest, float lum) {
dest.rgb *= vec3(lum);
// Clip back into the legal range
dest = clamp(dest, vec3(0.), vec3(1.0));
return dest;
}
"""
private const val MAIN_SHADER =
private const val SIMPLEX_SHADER =
"""
vec4 main(vec2 p) {
vec2 uv = p / in_size.xy;
@@ -71,8 +62,26 @@ class TurbulenceNoiseShader : RuntimeShader(TURBULENCE_NOISE_SHADER) {
}
"""
private const val TURBULENCE_NOISE_SHADER =
ShaderUtilLibrary.SHADER_LIB + UNIFORMS + SHADER_LIB + MAIN_SHADER
private const val FRACTAL_SHADER =
"""
vec4 main(vec2 p) {
vec2 uv = p / in_size.xy;
uv.x *= in_aspectRatio;
vec3 noiseP = vec3(uv + in_noiseMove.xy, in_noiseMove.z) * in_gridNum;
float luma = simplex3d_fractal(noiseP) * in_opacity;
vec3 mask = maskLuminosity(in_color.rgb, luma);
vec3 color = in_backgroundColor.rgb + mask * 0.6;
// Skip dithering.
return vec4(color * in_color.a, in_color.a);
}
"""
private const val SIMPLEX_NOISE_SHADER =
ShaderUtilLibrary.SHADER_LIB + UNIFORMS + SIMPLEX_SHADER
private const val FRACTAL_NOISE_SHADER =
ShaderUtilLibrary.SHADER_LIB + UNIFORMS + FRACTAL_SHADER
}
/** Sets the number of grid for generating noise. */

View File

@@ -0,0 +1,39 @@
/*
* 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.
*/
package com.android.systemui.surfaceeffects.turbulencenoise
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidTestingRunner::class)
class TurbulenceNoiseShaderTest : SysuiTestCase() {
private lateinit var turbulenceNoiseShader: TurbulenceNoiseShader
@Test
fun compliesSimplexNoise() {
turbulenceNoiseShader = TurbulenceNoiseShader()
}
@Test
fun compliesFractalNoise() {
turbulenceNoiseShader = TurbulenceNoiseShader(useFractal = true)
}
}