1/* 2 * Copyright (C) 2023 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 17// Copied from frameworks/base/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ 18// shaderutil/ShaderUtilLibrary.kt 19 20// Integer mod. 21int imod(int a, int b) { 22 return a - (b * (a / b)); 23} 24 25ivec3 imod(ivec3 a, int b) { 26 return ivec3(imod(a.x, b), imod(a.y, b), imod(a.z, b)); 27} 28 29// Integer based hash function with the return range of [-1, 1]. 30vec3 hash(vec3 p) { 31 ivec3 v = ivec3(p); 32 v = v * 1671731 + 10139267; 33 34 v.x += v.y * v.z; 35 v.y += v.z * v.x; 36 v.z += v.x * v.y; 37 38 ivec3 v2 = v / 65536; // v >> 16 39 v = imod((10 - imod((v + v2), 10)), 10); // v ^ v2 40 41 v.x += v.y * v.z; 42 v.y += v.z * v.x; 43 v.z += v.x * v.y; 44 45 // Use sin and cos to map the range to [-1, 1]. 46 return vec3(sin(float(v.x)), cos(float(v.y)), sin(float(v.z))); 47} 48 49// Skew factors (non-uniform). 50const float SKEW = 0.3333333; // 1/3 51const float UNSKEW = 0.1666667; // 1/6 52 53// Return range roughly [-1,1]. 54// It's because the hash function (that returns a random gradient vector) returns 55// different magnitude of vectors. Noise doesn't have to be in the precise range thus 56// skipped normalize. 57half simplex3d(vec3 p) { 58 // Skew the input coordinate, so that we get squashed cubical grid 59 vec3 s = floor(p + (p.x + p.y + p.z) * SKEW); 60 61 // Unskew back 62 vec3 u = s - (s.x + s.y + s.z) * UNSKEW; 63 64 // Unskewed coordinate that is relative to p, to compute the noise contribution 65 // based on the distance. 66 vec3 c0 = p - u; 67 68 // We have six simplices (in this case tetrahedron, since we are in 3D) that we 69 // could possibly in. 70 // Here, we are finding the correct tetrahedron (simplex shape), and traverse its 71 // four vertices (c0..3) when computing noise contribution. 72 // The way we find them is by comparing c0's x,y,z values. 73 // For example in 2D, we can find the triangle (simplex shape in 2D) that we are in 74 // by comparing x and y values. i.e. x>y lower, x<y, upper triangle. 75 // Same applies in 3D. 76 // 77 // Below indicates the offsets (or offset directions) when c0=(x0,y0,z0) 78 // x0>y0>z0: (1,0,0), (1,1,0), (1,1,1) 79 // x0>z0>y0: (1,0,0), (1,0,1), (1,1,1) 80 // z0>x0>y0: (0,0,1), (1,0,1), (1,1,1) 81 // z0>y0>x0: (0,0,1), (0,1,1), (1,1,1) 82 // y0>z0>x0: (0,1,0), (0,1,1), (1,1,1) 83 // y0>x0>z0: (0,1,0), (1,1,0), (1,1,1) 84 // 85 // The rule is: 86 // * For offset1, set 1 at the max component, otherwise 0. 87 // * For offset2, set 0 at the min component, otherwise 1. 88 // * For offset3, set 1 for all. 89 // 90 // Encode x0-y0, y0-z0, z0-x0 in a vec3 91 vec3 en = c0 - c0.yzx; 92 93 // Each represents whether x0>y0, y0>z0, z0>x0 94 en = step(vec3(0.), en); 95 96 // en.zxy encodes z0>x0, x0>y0, y0>x0 97 vec3 offset1 = en * (1. - en.zxy); // find max 98 vec3 offset2 = 1. - en.zxy * (1. - en); // 1-(find min) 99 vec3 offset3 = vec3(1.); 100 101 vec3 c1 = c0 - offset1 + UNSKEW; 102 vec3 c2 = c0 - offset2 + UNSKEW * 2.; 103 vec3 c3 = c0 - offset3 + UNSKEW * 3.; 104 105 // Kernel summation: dot(max(0, r^2-d^2))^4, noise contribution) 106 // 107 // First compute d^2, squared distance to the point. 108 vec4 w; // w = max(0, r^2 - d^2)) 109 w.x = dot(c0, c0); 110 w.y = dot(c1, c1); 111 w.z = dot(c2, c2); 112 w.w = dot(c3, c3); 113 114 // Noise contribution should decay to zero before they cross the simplex boundary. 115 // Usually r^2 is 0.5 or 0.6; 116 // 0.5 ensures continuity but 0.6 increases the visual quality for the application 117 // where discontinuity isn't noticeable. 118 w = max(0.6 - w, 0.); 119 120 // Noise contribution from each point. 121 vec4 nc; 122 nc.x = dot(hash(s), c0); 123 nc.y = dot(hash(s + offset1), c1); 124 nc.z = dot(hash(s + offset2), c2); 125 nc.w = dot(hash(s + offset3), c3); 126 127 nc *= w * w * w * w; 128 129 // Add all the noise contributions. 130 // Should multiply by the possible max contribution to adjust the range in [-1,1]. 131 return dot(vec4(32.), nc); 132} 133