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 17const float SKEW = 0.366025404; // (sqrt(3)-1)/2 18const float UNSKEW = 0.211324865; // (3-sqrt(3))/6 19 20half2 hash2d(vec2 p) { 21 p = vec2(dot(p,vec2(157.1, 235.7)), dot(p,vec2(573.5, 13.3))); 22 return fract(sin(p) * 877.343) * 2. -1.; // [-1, 1] 23} 24 25half hash1d(vec2 p) { 26 return fract(sin(dot(p, vec2(343.0, 49.0)))) * 2. -1.; // [-1, 1] 27} 28 29vec2 getVectorFromAngle(float theta) { 30 return vec2(cos(theta), sin(theta)); 31} 32 33int imod(int a, int b) { 34 return a - (b * (a / b)); 35} 36 37// 2D hash without bit-wise operations 38vec2 ihash2d(vec2 p) { 39 int a = int(p.x + p.y) * 15823; 40 int b = a * 65536; // a << 16 41 42 a = imod((10 - imod((a + b), 10)), 10); // a ^ b = (base - (a + b) % base) % base 43 a = (a * (a * a * 38833 + 683873) + 19734581); 44 a /= 65536; // a >> 16 45 46 float af = float(a); 47 return vec2(cos(af), sin(af)); 48} 49 50// Returns kernel summation from the given simplex vertices (v0, v1, v2), and their corresponding 51// gradients (g0, g1, g2). 52float kernel_summation(vec2 v0, vec2 v1, vec2 v2, vec2 g0, vec2 g1, vec2 g2) { 53 vec3 w = max(0.5 - vec3(dot(v0, v0), dot(v1, v1), dot(v2, v2)), 0.0); 54 55 w = w*w*w*w; 56 vec3 n = w * vec3(dot(v0, g0), dot(v1, g1), dot(v2, g2)); 57 58 return dot(n, vec3(32.0)); 59} 60 61// 2D Simplex noise with dynamic gradient vectors. Return value [-1, 1]. 62// 63// This method produces similar visuals to Simplex noise 3D, but at a lower computational cost. 64// The snapshot of the noise is the same as a regular Simplex noise. However, when animated, it 65// creates a swirling motion that is more suitable for flow-y effects. 66// 67// The difference in motion is not noticeable unless the following conditions are met: 68// 1) The rotation offset is identical for all vertex gradients. 69// 2) The noise is moving quickly. 70// 3) The noise is tiled. 71// 72// This method is recommended for use because it is significantly more performant than 3D Simplex 73// noise. It is especially useful for simulating fire, clouds, and fog, which all have advection. 74// 75// rot is an angle in radian that you want to step for each dt. 76float simplex2d_flow(vec2 p, float rot, float time) { 77 // Skew the input coordinate and find the simplex index. 78 vec2 i = floor(p + (p.x + p.y) * SKEW); 79 // First vertex of the triangle. 80 vec2 v0 = p - i + (i.x + i.y) * UNSKEW; 81 82 // Find two other vertices. 83 // Determines which triangle we should walk. 84 // If y>x, m=0 upper triangle, x>y, m=1 lower triangle. 85 float side = step(v0.y, v0.x); 86 vec2 walk = vec2(side, 1.0 - side); 87 88 vec2 v1 = v0 - walk + UNSKEW; 89 vec2 v2 = v0 - 1.0 + 2.*UNSKEW; 90 91 // Get random gradient vector. 92 vec2 g0 = ihash2d(i); 93 vec2 g1 = ihash2d(i+walk); 94 vec2 g2 = ihash2d(i+1.0); 95 96 // Make the gradient vectors dynamic by adding rotations. 97 g0 += getVectorFromAngle(rot * time * hash1d(i)); 98 g1 += getVectorFromAngle(rot * time * hash1d(i+walk)); 99 g2 += getVectorFromAngle(rot * time * hash1d(i+1.)); 100 101 return kernel_summation(v0, v1, v2, g0, g1, g2); 102} 103 104// 2D Simplex noise 105float simplex2d(vec2 p) { 106 // Skew the input coordinate and find the simplex index. 107 vec2 i = floor(p + (p.x + p.y) * SKEW); 108 // First vertex of the triangle. 109 vec2 v0 = p - i + (i.x + i.y) * UNSKEW; 110 111 // Find two other vertices. 112 // Determines which triangle we should walk. 113 // If y>x, m=0 upper triangle, x>y, m=1 lower triangle. 114 float side = step(v0.y, v0.x); 115 vec2 walk = vec2(side, 1.0 - side); 116 117 vec2 v1 = v0 - walk + UNSKEW; 118 vec2 v2 = v0 - 1.0 + 2.*UNSKEW; 119 120 // Get random gradient vector. 121 vec2 g0 = ihash2d(i); 122 vec2 g1 = ihash2d(i+walk); 123 vec2 g2 = ihash2d(i+1.0); 124 125 return kernel_summation(v0, v1, v2, g0, g1, g2); 126} 127