| … | … | @@ -1,49 +1,42 @@ |
| 1 | 1 | // ============================================================================ |
| 2 | 2 | // ASHIMA SIMPLEX -- ONE TEXT, COMPILED AS BOTH GLSL AND C++. |
| 3 | 3 | // |
| 4 | | // ⚠ THIS ONE IS NOT BLENDER'S. Blender's Noise Texture is Perlin |
| 5 | | // (blender_perlin.inc); this is the Ashima Arts polynomial-permutation simplex |
| 6 | | // that proc-nodes' own "Simplex Noise" node uses, and that blender-bridge |
| 7 | | // reproduces on the Blender side as the ProcNodes_SimplexNoise node group. It |
| 8 | | // lives here for the same reason the others do: it existed TWICE, as a |
| 9 | | // file-local C++ copy in noise_nodes.cpp and as a hand-written GLSL copy in |
| 10 | | // GpuCompiler's hand-written noise library, and nothing compared them. |
| 4 | // ⚠ NOT BLENDER'S. Blender's Noise Texture is Perlin (blender_perlin.inc); |
| 5 | // this is the Ashima Arts / webgl-noise `snoise` that proc-nodes' own Simplex |
| 6 | // Noise node uses, and that blender-bridge mirrors as the |
| 7 | // ProcNodes_SimplexNoise group. |
| 11 | 8 | // |
| 12 | | // IEEE 754 deterministic: no lookup tables, no sin(), only multiply, add, mod, |
| 13 | | // floor and dot -- which is why the same text can run on both machines. |
| 9 | // --------------------------------------------------------------------------- |
| 10 | // ⛔ THIS FILE REPLACES A BROKEN SCALAR PORT, AND THE HISTORY IS THE POINT. |
| 14 | 11 | // |
| 15 | | // TRANSFORMED from the C++ that was in noise_nodes.cpp, not retyped. The |
| 16 | | // equivalence run against that original is what says the transformation was |
| 17 | | // faithful. |
| 12 | // proc-nodes had TWO implementations: a hand-written GLSL copy of the vector |
| 13 | // form below, and a file-local C++ "scalarisation" of it in noise_nodes.cpp. |
| 14 | // They were never compared -- and they were not the same function: |
| 18 | 15 | // |
| 19 | | // ⛔ THIS FUNCTION IS BROKEN, AND IT WAS BROKEN BEFORE IT MOVED HERE. |
| 16 | // scalar C++ (CPU) simplex(1.20, 0.36, 2.04) = 5557.13 |
| 17 | // vector GLSL (GPU) simplex(1.20, 0.36, 2.04) = -0.5551 |
| 20 | 18 | // |
| 21 | | // It returns values in the THOUSANDS where a simplex must be in [-1, 1]: |
| 19 | // The CPU was out of range by four orders of magnitude, so the node's Value |
| 20 | // output -- documented 0..1 -- was in the thousands on the CPU and correct on |
| 21 | // the GPU. Every mesh baked on the CPU had different noise from the same graph |
| 22 | // rendered on the GPU, and nothing in the codebase could see it. |
| 22 | 23 | // |
| 23 | | // simplex(0.50, 0.15, 0.85) = -7349.26 |
| 24 | | // simplex(1.20, 0.36, 2.04) = 5557.13 |
| 25 | | // fbm, 4 octaves = 15221.4 |
| 24 | // TWO THINGS BROKE IN THE SCALARISATION, both visible above: |
| 26 | 25 | // |
| 27 | | // and SimplexNoiseNode maps that as n * 0.5 + 0.5, so its "Value" output -- |
| 28 | | // documented 0..1 -- is 7611 for an ordinary point. Not a large-coordinate |
| 29 | | // precision effect: the range is ~±1e5 at EVERY magnitude tested, |p| ~ 1 |
| 30 | | // included. Something in the port of Ashima's gradient or its 105.0 scaling is |
| 31 | | // wrong. |
| 26 | // 1. THE GRADIENT CONSTANTS. `ns = n_ * D.wyz - D.xzx` with D = (0, .5, 1, 2) |
| 27 | // is (2/7, 0.5/7 - 1, 1/7) = (0.2857, -0.9286, 0.1429). The scalar copy |
| 28 | // used (2/7, -1.0, 0.5/7) -- two of the three wrong. |
| 32 | 29 | // |
| 33 | | // ⚠ NOT INTRODUCED BY THE MOVE. This text is bit-identical to the file-local |
| 34 | | // C++ it replaced -- 240000/240000 -- and the hand-written GLSL twin agreed |
| 35 | | // with it too, which is exactly why nobody noticed: both implementations were |
| 36 | | // wrong in the same way, and a bridge that compares them to each other cannot |
| 37 | | // see it. It took comparing against the DEFINITION of a simplex to find. |
| 30 | // 2. THE LANE SHUFFLES CANNOT BE DONE PER CORNER. `b0 = vec4(x.xy, y.xy)` |
| 31 | // and `a0 = b0.xzyw + s0.xzyw * sh.xxyy` mix the x and y components of |
| 32 | // DIFFERENT corners into one vec4. A per-corner scalar rewrite has no way |
| 33 | // to express that, which is why the scalarisation was doomed rather than |
| 34 | // merely mistyped. |
| 38 | 35 | // |
| 39 | | // The parity gate therefore covers what it can honestly hold -- the raw |
| 40 | | // lattice and low octave counts, where CPU and GPU agree to 1e-5 -- and stops |
| 41 | | // short of pretending the accumulated fbm is meaningful. Fixing the arithmetic |
| 42 | | // changes what the node outputs and is its own change. |
| 43 | | // |
| 44 | | // THE SUBSET: the per-corner gradient was a LAMBDA with three reference |
| 45 | | // out-parameters. GLSL has neither, so it is a function returning a vec3; its |
| 46 | | // captures were constants derived from 1/7 and are recomputed inside it. |
| 36 | // So this file is the VECTOR form -- the one that was right -- with every |
| 37 | // swizzle written out as an explicit constructor, because GLSL has swizzles |
| 38 | // and C++ does not. `vec3(x0.y, x0.z, x0.x)` is what `x0.yzx` means and both |
| 39 | // languages accept it. |
| 47 | 40 | // ============================================================================ |
| 48 | 41 | |
| 49 | 42 | #ifndef PN_PROC_SIMPLEX |
| … | … | @@ -53,162 +46,111 @@ |
| 53 | 46 | #define BN_FN |
| 54 | 47 | #endif |
| 55 | 48 | |
| 56 | | // --- Simplex noise implementation (3D) --- |
| 57 | | // Ashima Arts polynomial permutation — matches GPU (gpu_compiler.cpp) and |
| 58 | | // Blender GeoNodes ProcNodes_SimplexNoise group. IEEE 754 deterministic: |
| 59 | | // no lookup tables, no sin(), only multiply/add/mod/floor/dot. |
| 49 | BN_FN vec3 ps_mod289_v3(vec3 x) { |
| 50 | return x - floor(x * (1.0f / 289.0f)) * 289.0f; |
| 51 | } |
| 60 | 52 | |
| 61 | | BN_FN float ps_mod289(float x) { |
| 53 | BN_FN vec4 ps_mod289_v4(vec4 x) { |
| 62 | 54 | return x - floor(x * (1.0f / 289.0f)) * 289.0f; |
| 63 | 55 | } |
| 64 | 56 | |
| 65 | | BN_FN float ps_permute(float x) { |
| 66 | | return ps_mod289(((x * 34.0f) + 10.0f) * x); |
| 57 | BN_FN vec4 ps_permute(vec4 x) { |
| 58 | return ps_mod289_v4(((x * 34.0f) + 10.0f) * x); |
| 67 | 59 | } |
| 68 | 60 | |
| 69 | | BN_FN float ps_taylor_inv_sqrt(float r) { |
| 61 | BN_FN vec4 ps_taylor_inv_sqrt(vec4 r) { |
| 70 | 62 | return 1.79284291400159f - 0.85373472095314f * r; |
| 71 | 63 | } |
| 72 | 64 | |
| 73 | | BN_FN float ps_dot3(float ax, float ay, float az, float bx, float by, float bz) { |
| 74 | | return ax * bx + ay * by + az * bz; |
| 75 | | } |
| 65 | BN_FN float ps_simplex_noise_3d_v(vec3 v) { |
| 66 | // C = (1/6, 1/3), D = (0, 0.5, 1, 2) in the original; written out below |
| 67 | // wherever a swizzle of them was used. |
| 68 | float Cx = 1.0f / 6.0f; |
| 69 | float Cy = 1.0f / 3.0f; |
| 76 | 70 | |
| 77 | | BN_FN vec3 ps_grad_from_p(float pv) { |
| 78 | | float n_ = 1.0f / 7.0f; |
| 79 | | float ns_xx = 2.0f * n_; |
| 80 | | float ns_yy = -1.0f; |
| 81 | | float ns_zz = 0.5f * n_; |
| 82 | | float gx; float gy; float gz; |
| 83 | | |
| 84 | | float j = pv - 49.0f * floor(pv * ns_zz * ns_zz); |
| 85 | | float x_ = floor(j * ns_zz); |
| 86 | | float y_ = floor(j - 7.0f * x_); |
| 87 | | float gxx = x_ * ns_xx + ns_yy; |
| 88 | | float gyy = y_ * ns_xx + ns_yy; |
| 89 | | float hh = 1.0f - abs(gxx) - abs(gyy); |
| 90 | | |
| 91 | | // Sign correction |
| 92 | | float sx = (gxx < 0.0f) ? -1.0f : 1.0f; |
| 93 | | float sy = (gyy < 0.0f) ? -1.0f : 1.0f; |
| 94 | | float b0x = gxx; |
| 95 | | float b0y = gyy; |
| 96 | | float sh = (hh < 0.0f) ? -1.0f : 0.0f; |
| 97 | | gx = b0x + floor(b0x) * 2.0f * sh + sh; |
| 98 | | // Simpler: match GLSL exactly |
| 99 | | // a0 = b0.xzyw + s0.xzyw * sh.xxyy |
| 100 | | // For a single corner, this simplifies to: |
| 101 | | float s0x = floor(b0x) * 2.0f + 1.0f; |
| 102 | | float s0y = floor(b0y) * 2.0f + 1.0f; |
| 103 | | float shv = (hh < 0.0f) ? -1.0f : 0.0f; |
| 104 | | gx = b0x + s0x * shv; |
| 105 | | gy = b0y + s0y * shv; |
| 106 | | gz = hh; |
| 107 | | |
| 108 | | // Normalize |
| 109 | | float len2 = gx * gx + gy * gy + gz * gz; |
| 110 | | float inv_len = ps_taylor_inv_sqrt(len2); |
| 111 | | gx *= inv_len; |
| 112 | | gy *= inv_len; |
| 113 | | gz *= inv_len; |
| 114 | | return vec3(gx, gy, gz); |
| 71 | // First corner |
| 72 | vec3 i = floor(v + vec3(dot(v, vec3(Cy, Cy, Cy)))); |
| 73 | vec3 x0 = v - i + vec3(dot(i, vec3(Cx, Cx, Cx))); |
| 74 | |
| 75 | // Other corners |
| 76 | vec3 g = step(vec3(x0.y, x0.z, x0.x), vec3(x0.x, x0.y, x0.z)); |
| 77 | vec3 l = 1.0f - g; |
| 78 | vec3 i1 = min(vec3(g.x, g.y, g.z), vec3(l.z, l.x, l.y)); |
| 79 | vec3 i2 = max(vec3(g.x, g.y, g.z), vec3(l.z, l.x, l.y)); |
| 80 | |
| 81 | vec3 x1 = x0 - i1 + vec3(Cx, Cx, Cx); |
| 82 | vec3 x2 = x0 - i2 + vec3(Cy, Cy, Cy); |
| 83 | vec3 x3 = x0 - vec3(0.5f, 0.5f, 0.5f); // D.yyy |
| 84 | |
| 85 | // Permutations |
| 86 | i = ps_mod289_v3(i); |
| 87 | vec4 p = ps_permute(ps_permute(ps_permute( |
| 88 | vec4(i.z, i.z, i.z, i.z) + vec4(0.0f, i1.z, i2.z, 1.0f)) |
| 89 | + vec4(i.y, i.y, i.y, i.y) + vec4(0.0f, i1.y, i2.y, 1.0f)) |
| 90 | + vec4(i.x, i.x, i.x, i.x) + vec4(0.0f, i1.x, i2.x, 1.0f)); |
| 91 | |
| 92 | // Gradients: 7x7 points over a square, mapped onto an octahedron. |
| 93 | // ⛔ ns = n_ * D.wyz - D.xzx = n_ * (2, 0.5, 1) - (0, 1, 0). The scalar |
| 94 | // port that this file replaces got two of these three wrong. |
| 95 | float n_ = 0.142857142857f; // 1/7 |
| 96 | vec3 ns = vec3(n_ * 2.0f - 0.0f, n_ * 0.5f - 1.0f, n_ * 1.0f - 0.0f); |
| 97 | |
| 98 | vec4 j = p - 49.0f * floor(p * ns.z * ns.z); |
| 99 | |
| 100 | vec4 x_ = floor(j * ns.z); |
| 101 | vec4 y_ = floor(j - 7.0f * x_); |
| 102 | |
| 103 | vec4 x = x_ * ns.x + vec4(ns.y, ns.y, ns.y, ns.y); |
| 104 | vec4 y = y_ * ns.x + vec4(ns.y, ns.y, ns.y, ns.y); |
| 105 | vec4 h = 1.0f - abs(x) - abs(y); |
| 106 | |
| 107 | // ⛔ THE LANES CROSS HERE. b0 holds x.xy and y.xy -- two components of one |
| 108 | // corner pair and two of another -- and a0 then shuffles them again. This |
| 109 | // is what a per-corner scalarisation cannot represent. |
| 110 | vec4 b0 = vec4(x.x, x.y, y.x, y.y); |
| 111 | vec4 b1 = vec4(x.z, x.w, y.z, y.w); |
| 112 | |
| 113 | vec4 s0 = floor(b0) * 2.0f + 1.0f; |
| 114 | vec4 s1 = floor(b1) * 2.0f + 1.0f; |
| 115 | vec4 sh = -step(h, vec4(0.0f)); |
| 116 | |
| 117 | vec4 a0 = vec4(b0.x, b0.z, b0.y, b0.w) + |
| 118 | vec4(s0.x, s0.z, s0.y, s0.w) * vec4(sh.x, sh.x, sh.y, sh.y); |
| 119 | vec4 a1 = vec4(b1.x, b1.z, b1.y, b1.w) + |
| 120 | vec4(s1.x, s1.z, s1.y, s1.w) * vec4(sh.z, sh.z, sh.w, sh.w); |
| 121 | |
| 122 | vec3 p0 = vec3(a0.x, a0.y, h.x); |
| 123 | vec3 p1 = vec3(a0.z, a0.w, h.y); |
| 124 | vec3 p2 = vec3(a1.x, a1.y, h.z); |
| 125 | vec3 p3 = vec3(a1.z, a1.w, h.w); |
| 126 | |
| 127 | // Normalise gradients |
| 128 | vec4 norm = ps_taylor_inv_sqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); |
| 129 | p0 *= norm.x; |
| 130 | p1 *= norm.y; |
| 131 | p2 *= norm.z; |
| 132 | p3 *= norm.w; |
| 133 | |
| 134 | // Mix contributions from the four corners |
| 135 | vec4 m = max(0.5f - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), vec4(0.0f)); |
| 136 | m = m * m; |
| 137 | return 105.0f * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3))); |
| 115 | 138 | } |
| 116 | 139 | |
| 117 | | BN_FN float ps_simplex_noise_3d(float xin, float yin, float zin) { |
| 118 | | float C1 = 1.0f / 6.0f; // G3 |
| 119 | | float C2 = 1.0f / 3.0f; // F3 |
| 120 | | |
| 121 | | // First corner |
| 122 | | float s = (xin + yin + zin) * C2; |
| 123 | | float ix = floor(xin + s); |
| 124 | | float iy = floor(yin + s); |
| 125 | | float iz = floor(zin + s); |
| 126 | | |
| 127 | | float t = (ix + iy + iz) * C1; |
| 128 | | float x0 = xin - ix + t; |
| 129 | | float y0 = yin - iy + t; |
| 130 | | float z0 = zin - iz + t; |
| 131 | | |
| 132 | | // Simplex traversal (branchless Ashima step/min/max) |
| 133 | | float gx = (x0 >= y0) ? 1.0f : 0.0f; // step(y0, x0) |
| 134 | | float gy = (y0 >= z0) ? 1.0f : 0.0f; // step(z0, y0) |
| 135 | | float gz = (z0 >= x0) ? 1.0f : 0.0f; // step(x0, z0) |
| 136 | | float lx = 1.0f - gx; |
| 137 | | float ly = 1.0f - gy; |
| 138 | | float lz = 1.0f - gz; |
| 139 | | |
| 140 | | float i1x = min(gx, lz); |
| 141 | | float i1y = min(gy, lx); |
| 142 | | float i1z = min(gz, ly); |
| 143 | | float i2x = max(gx, lz); |
| 144 | | float i2y = max(gy, lx); |
| 145 | | float i2z = max(gz, ly); |
| 146 | | |
| 147 | | float x1 = x0 - i1x + C1; |
| 148 | | float y1 = y0 - i1y + C1; |
| 149 | | float z1 = z0 - i1z + C1; |
| 150 | | float x2 = x0 - i2x + C2; |
| 151 | | float y2 = y0 - i2y + C2; |
| 152 | | float z2 = z0 - i2z + C2; |
| 153 | | float x3 = x0 - 0.5f; |
| 154 | | float y3 = y0 - 0.5f; |
| 155 | | float z3 = z0 - 0.5f; |
| 156 | | |
| 157 | | // Permutations (polynomial, no lookup table) |
| 158 | | ix = ps_mod289(ix); |
| 159 | | iy = ps_mod289(iy); |
| 160 | | iz = ps_mod289(iz); |
| 161 | | |
| 162 | | float p0 = ps_permute(ps_permute(ps_permute(iz) + iy) + ix); |
| 163 | | float p1 = ps_permute(ps_permute(ps_permute(iz + i1z) + iy + i1y) + ix + i1x); |
| 164 | | float p2 = ps_permute(ps_permute(ps_permute(iz + i2z) + iy + i2y) + ix + i2x); |
| 165 | | float p3 = ps_permute(ps_permute(ps_permute(iz + 1.0f) + iy + 1.0f) + ix + 1.0f); |
| 166 | | |
| 167 | | // Gradients: 7x7 points over octahedron |
| 168 | | float n_ = 1.0f / 7.0f; |
| 169 | | // ns = n_ * D.wyz - D.xzx where D = (0, 0.5, 1, 2) |
| 170 | | float ns_x = n_ * 2.0f - 0.0f; // 2/7 |
| 171 | | float ns_y = n_ * 0.5f - 1.0f; // -0.928571... |
| 172 | | float ns_z = n_ * 0.0f - 0.0f; // 0 -- wait, let me recalculate |
| 173 | | // D.wyz = (2.0, 0.0, 0.5), D.xzx = (0.0, 1.0, 0.0) |
| 174 | | // ns = n_ * (2.0, 0.0, 0.5) - (0.0, 1.0, 0.0) |
| 175 | | // ns = (2/7, -1, 1/14) = (0.285714, -1.0, 0.071428) |
| 176 | | float ns_xx = 2.0f * n_; // 0.285714 |
| 177 | | float ns_yy = -1.0f; // -1.0 |
| 178 | | float ns_zz = 0.5f * n_; // 0.071428 |
| 179 | | |
| 180 | | // For each corner, compute gradient from permutation value |
| 181 | | |
| 182 | | float g0x, g0y, g0z, g1x, g1y, g1z, g2x, g2y, g2z, g3x, g3y, g3z; |
| 183 | | vec3 p0_v = ps_grad_from_p(p0); g0x = p0_v.x; g0y = p0_v.y; g0z = p0_v.z; |
| 184 | | vec3 p1_v = ps_grad_from_p(p1); g1x = p1_v.x; g1y = p1_v.y; g1z = p1_v.z; |
| 185 | | vec3 p2_v = ps_grad_from_p(p2); g2x = p2_v.x; g2y = p2_v.y; g2z = p2_v.z; |
| 186 | | vec3 p3_v = ps_grad_from_p(p3); g3x = p3_v.x; g3y = p3_v.y; g3z = p3_v.z; |
| 187 | | |
| 188 | | // Mix contributions from four corners |
| 189 | | float m0 = max(0.5f - ps_dot3(x0, y0, z0, x0, y0, z0), 0.0f); |
| 190 | | float m1 = max(0.5f - ps_dot3(x1, y1, z1, x1, y1, z1), 0.0f); |
| 191 | | float m2 = max(0.5f - ps_dot3(x2, y2, z2, x2, y2, z2), 0.0f); |
| 192 | | float m3 = max(0.5f - ps_dot3(x3, y3, z3, x3, y3, z3), 0.0f); |
| 193 | | |
| 194 | | m0 *= m0; m1 *= m1; m2 *= m2; m3 *= m3; |
| 195 | | |
| 196 | | return 105.0f * ( |
| 197 | | m0 * m0 * ps_dot3(g0x, g0y, g0z, x0, y0, z0) + |
| 198 | | m1 * m1 * ps_dot3(g1x, g1y, g1z, x1, y1, z1) + |
| 199 | | m2 * m2 * ps_dot3(g2x, g2y, g2z, x2, y2, z2) + |
| 200 | | m3 * m3 * ps_dot3(g3x, g3y, g3z, x3, y3, z3)); |
| 140 | // The scalar entry point the nodes call, so the call sites did not change. |
| 141 | BN_FN float ps_simplex_noise_3d(float x, float y, float z) { |
| 142 | return ps_simplex_noise_3d_v(vec3(x, y, z)); |
| 201 | 143 | } |
| 202 | 144 | |
| 203 | | // fBM (fractal Brownian motion) using simplex noise |
| 204 | | BN_FN float ps_fbm_noise_3d(float x, float y, float z, int octaves, float roughness, float lacunarity) { |
| 145 | BN_FN float ps_fbm_noise_3d(float x, float y, float z, int octaves, float roughness, |
| 146 | float lacunarity) { |
| 205 | 147 | float value = 0.0f; |
| 206 | 148 | float amplitude = 1.0f; |
| 207 | 149 | float frequency = 1.0f; |
| 208 | 150 | float max_amp = 0.0f; |
| 209 | 151 | |
| 210 | 152 | for (int i = 0; i < octaves; i++) { |
| 211 | | value += amplitude * ps_simplex_noise_3d(x * frequency, y * frequency, z * frequency); |
| 153 | value += amplitude * ps_simplex_noise_3d_v(vec3(x, y, z) * frequency); |
| 212 | 154 | max_amp += amplitude; |
| 213 | 155 | amplitude *= roughness; |
| 214 | 156 | frequency *= lacunarity; |