diff options
Diffstat (limited to 'weathereffects/assets/shaders/simplex3d.agsl')
-rw-r--r-- | weathereffects/assets/shaders/simplex3d.agsl | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/weathereffects/assets/shaders/simplex3d.agsl b/weathereffects/assets/shaders/simplex3d.agsl new file mode 100644 index 0000000..7c696f9 --- /dev/null +++ b/weathereffects/assets/shaders/simplex3d.agsl @@ -0,0 +1,110 @@ +/* + * 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. + */ + +// Copied from frameworks/base/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ +// shaderutil/ShaderUtilLibrary.kt + +// Return range [-1, 1]. +vec3 hash(vec3 p) { + p = fract(p * vec3(.3456, .1234, .9876)); + p += dot(p, p.yxz + 43.21); + p = (p.xxy + p.yxx) * p.zyx; + return (fract(sin(p) * 4567.1234567) - .5) * 2.; +} +// Skew factors (non-uniform). +const float SKEW = 0.3333333; // 1/3 +const float 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) { + // Skew the input coordinate, so that we get squashed cubical grid + vec3 s = floor(p + (p.x + p.y + p.z) * SKEW); + + // Unskew back + vec3 u = s - (s.x + s.y + s.z) * UNSKEW; + + // Unskewed coordinate that is relative to p, to compute the noise contribution + // based on the distance. + vec3 c0 = p - u; + + // We have six simplices (in this case tetrahedron, since we are in 3D) that we + // could possibly in. + // Here, we are finding the correct tetrahedron (simplex shape), and traverse its + // four vertices (c0..3) when computing noise contribution. + // The way we find them is by comparing c0's x,y,z values. + // For example in 2D, we can find the triangle (simplex shape in 2D) that we are in + // by comparing x and y values. i.e. x>y lower, x<y, upper triangle. + // Same applies in 3D. + // + // Below indicates the offsets (or offset directions) when c0=(x0,y0,z0) + // x0>y0>z0: (1,0,0), (1,1,0), (1,1,1) + // x0>z0>y0: (1,0,0), (1,0,1), (1,1,1) + // z0>x0>y0: (0,0,1), (1,0,1), (1,1,1) + // z0>y0>x0: (0,0,1), (0,1,1), (1,1,1) + // y0>z0>x0: (0,1,0), (0,1,1), (1,1,1) + // y0>x0>z0: (0,1,0), (1,1,0), (1,1,1) + // + // The rule is: + // * For offset1, set 1 at the max component, otherwise 0. + // * For offset2, set 0 at the min component, otherwise 1. + // * For offset3, set 1 for all. + // + // Encode x0-y0, y0-z0, z0-x0 in a vec3 + vec3 en = c0 - c0.yzx; + + // Each represents whether x0>y0, y0>z0, z0>x0 + en = step(vec3(0.), en); + + // en.zxy encodes z0>x0, x0>y0, y0>x0 + vec3 offset1 = en * (1. - en.zxy); // find max + vec3 offset2 = 1. - en.zxy * (1. - en); // 1-(find min) + vec3 offset3 = vec3(1.); + + vec3 c1 = c0 - offset1 + UNSKEW; + vec3 c2 = c0 - offset2 + UNSKEW * 2.; + vec3 c3 = c0 - offset3 + UNSKEW * 3.; + + // Kernel summation: dot(max(0, r^2-d^2))^4, noise contribution) + // + // First compute d^2, squared distance to the point. + vec4 w; // w = max(0, r^2 - d^2)) + w.x = dot(c0, c0); + w.y = dot(c1, c1); + w.z = dot(c2, c2); + w.w = dot(c3, c3); + + // Noise contribution should decay to zero before they cross the simplex boundary. + // Usually r^2 is 0.5 or 0.6; + // 0.5 ensures continuity but 0.6 increases the visual quality for the application + // where discontinuity isn't noticeable. + w = max(0.6 - w, 0.); + + // Noise contribution from each point. + vec4 nc; + nc.x = dot(hash(s), c0); + nc.y = dot(hash(s + offset1), c1); + nc.z = dot(hash(s + offset2), c2); + nc.w = dot(hash(s + offset3), c3); + + nc *= w * w * w * w; + + // Add all the noise contributions. + // Should multiply by the possible max contribution to adjust the range in [-1,1]. + return dot(vec4(32.), nc); +} |