• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.systemui.surfaceeffects.shaderutil
17 
18 /** A common utility functions that are used for computing shaders. */
19 class ShaderUtilLibrary {
20     // language=AGSL
21     companion object {
22         const val SHADER_LIB =
23             """
24             float triangleNoise(vec2 n) {
25                 n  = fract(n * vec2(5.3987, 5.4421));
26                 n += dot(n.yx, n.xy + vec2(21.5351, 14.3137));
27                 float xy = n.x * n.y;
28                 // compute in [0..2[ and remap to [-1.0..1.0[
29                 return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;
30             }
31 
32             const float PI = 3.1415926535897932384626;
33 
34             float sparkles(vec2 uv, float t) {
35                 float n = triangleNoise(uv);
36                 float s = 0.0;
37                 for (float i = 0; i < 4; i += 1) {
38                     float l = i * 0.01;
39                     float h = l + 0.1;
40                     float o = smoothstep(n - l, h, n);
41                     o *= abs(sin(PI * o * (t + 0.55 * i)));
42                     s += o;
43                 }
44                 return s;
45             }
46 
47             vec2 distort(vec2 p, float time, float distort_amount_radial,
48                 float distort_amount_xy) {
49                     float angle = atan(p.y, p.x);
50                       return p + vec2(sin(angle * 8 + time * 0.003 + 1.641),
51                                 cos(angle * 5 + 2.14 + time * 0.00412)) * distort_amount_radial
52                          + vec2(sin(p.x * 0.01 + time * 0.00215 + 0.8123),
53                                 cos(p.y * 0.01 + time * 0.005931)) * distort_amount_xy;
54             }
55 
56             // Return range [-1, 1].
57             vec3 hash(vec3 p) {
58                 p = fract(p * vec3(.3456, .1234, .9876));
59                 p += dot(p, p.yxz + 43.21);
60                 p = (p.xxy + p.yxx) * p.zyx;
61                 return (fract(sin(p) * 4567.1234567) - .5) * 2.;
62             }
63 
64             // Skew factors (non-uniform).
65             const float SKEW = 0.3333333;  // 1/3
66             const float UNSKEW = 0.1666667;  // 1/6
67 
68             // Return range roughly [-1,1].
69             // It's because the hash function (that returns a random gradient vector) returns
70             // different magnitude of vectors. Noise doesn't have to be in the precise range thus
71             // skipped normalize.
72             float simplex3d(vec3 p) {
73                 // Skew the input coordinate, so that we get squashed cubical grid
74                 vec3 s = floor(p + (p.x + p.y + p.z) * SKEW);
75 
76                 // Unskew back
77                 vec3 u = s - (s.x + s.y + s.z) * UNSKEW;
78 
79                 // Unskewed coordinate that is relative to p, to compute the noise contribution
80                 // based on the distance.
81                 vec3 c0 = p - u;
82 
83                 // We have six simplices (in this case tetrahedron, since we are in 3D) that we
84                 // could possibly in.
85                 // Here, we are finding the correct tetrahedron (simplex shape), and traverse its
86                 // four vertices (c0..3) when computing noise contribution.
87                 // The way we find them is by comparing c0's x,y,z values.
88                 // For example in 2D, we can find the triangle (simplex shape in 2D) that we are in
89                 // by comparing x and y values. i.e. x>y lower, x<y, upper triangle.
90                 // Same applies in 3D.
91                 //
92                 // Below indicates the offsets (or offset directions) when c0=(x0,y0,z0)
93                 // x0>y0>z0: (1,0,0), (1,1,0), (1,1,1)
94                 // x0>z0>y0: (1,0,0), (1,0,1), (1,1,1)
95                 // z0>x0>y0: (0,0,1), (1,0,1), (1,1,1)
96                 // z0>y0>x0: (0,0,1), (0,1,1), (1,1,1)
97                 // y0>z0>x0: (0,1,0), (0,1,1), (1,1,1)
98                 // y0>x0>z0: (0,1,0), (1,1,0), (1,1,1)
99                 //
100                 // The rule is:
101                 // * For offset1, set 1 at the max component, otherwise 0.
102                 // * For offset2, set 0 at the min component, otherwise 1.
103                 // * For offset3, set 1 for all.
104                 //
105                 // Encode x0-y0, y0-z0, z0-x0 in a vec3
106                 vec3 en = c0 - c0.yzx;
107                 // Each represents whether x0>y0, y0>z0, z0>x0
108                 en = step(vec3(0.), en);
109                 // en.zxy encodes z0>x0, x0>y0, y0>x0
110                 vec3 offset1 = en * (1. - en.zxy); // find max
111                 vec3 offset2 = 1. - en.zxy * (1. - en); // 1-(find min)
112                 vec3 offset3 = vec3(1.);
113 
114                 vec3 c1 = c0 - offset1 + UNSKEW;
115                 vec3 c2 = c0 - offset2 + UNSKEW * 2.;
116                 vec3 c3 = c0 - offset3 + UNSKEW * 3.;
117 
118                 // Kernel summation: dot(max(0, r^2-d^2))^4, noise contribution)
119                 //
120                 // First compute d^2, squared distance to the point.
121                 vec4 w; // w = max(0, r^2 - d^2))
122                 w.x = dot(c0, c0);
123                 w.y = dot(c1, c1);
124                 w.z = dot(c2, c2);
125                 w.w = dot(c3, c3);
126 
127                 // Noise contribution should decay to zero before they cross the simplex boundary.
128                 // Usually r^2 is 0.5 or 0.6;
129                 // 0.5 ensures continuity but 0.6 increases the visual quality for the application
130                 // where discontinuity isn't noticeable.
131                 w = max(0.6 - w, 0.);
132 
133                 // Noise contribution from each point.
134                 vec4 nc;
135                 nc.x = dot(hash(s), c0);
136                 nc.y = dot(hash(s + offset1), c1);
137                 nc.z = dot(hash(s + offset2), c2);
138                 nc.w = dot(hash(s + offset3), c3);
139 
140                 nc *= w*w*w*w;
141 
142                 // Add all the noise contributions.
143                 // Should multiply by the possible max contribution to adjust the range in [-1,1].
144                 return dot(vec4(32.), nc);
145             }
146             """
147     }
148 }
149