|
| 1 | +#pragma once |
| 2 | + |
| 3 | +#include "dang-math/vector.h" |
| 4 | + |
| 5 | +#include "dang-utils/utils.h" |
| 6 | + |
| 7 | +namespace dang::math::noise { |
| 8 | + |
| 9 | +// Converted from https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83 |
| 10 | + |
| 11 | +/// @brief A permutation seed, which is used by simplex noise generation. |
| 12 | +/// @remark Values wrap around in the range [0..289) and should be integers |
| 13 | +struct PermuteFactors { |
| 14 | + float f1 = 1.0f; |
| 15 | + float f2 = 34.0f; |
| 16 | + |
| 17 | + /// @brief Selects one of the 82944 distinct factors from the given integral seed. |
| 18 | + template <typename T> |
| 19 | + static PermuteFactors fromSeed(T seed) |
| 20 | + { |
| 21 | + static_assert(std::is_integral_v<T>); |
| 22 | + auto seed_unsigned = static_cast<std::make_unsigned_t<T>>(seed); |
| 23 | + auto x = dutils::removeOddBits(seed_unsigned); |
| 24 | + auto y = dutils::removeOddBits(seed_unsigned >> 1); |
| 25 | + auto a = 1 + x % 288; |
| 26 | + auto b = 1 + y % 288; |
| 27 | + return {static_cast<float>(a), static_cast<float>(b)}; |
| 28 | + } |
| 29 | +}; |
| 30 | + |
| 31 | +namespace detail { |
| 32 | + |
| 33 | +template <std::size_t v_dim> |
| 34 | +[[nodiscard]] constexpr vec<v_dim> permute(vec<v_dim> x, const PermuteFactors& factors) |
| 35 | +{ |
| 36 | + return ((x * factors.f2 + factors.f1) * x).mod(289.0f); |
| 37 | +} |
| 38 | + |
| 39 | +[[nodiscard]] constexpr float permute(float x, const PermuteFactors& factors) { return permute(vec1(x), factors).x(); } |
| 40 | + |
| 41 | +template <std::size_t v_dim> |
| 42 | +[[nodiscard]] constexpr vec<v_dim> taylorInvSqrt(vec<v_dim> r) |
| 43 | +{ |
| 44 | + return 1.79284291400159f - 0.85373472095314f * r; |
| 45 | +} |
| 46 | + |
| 47 | +[[nodiscard]] constexpr float taylorInvSqrt(float x) { return taylorInvSqrt(vec1(x)).x(); } |
| 48 | + |
| 49 | +[[nodiscard]] constexpr vec4 grad4(float j, vec4 ip) |
| 50 | +{ |
| 51 | + constexpr vec4 ones = vec4(1.0, 1.0, 1.0, -1.0); |
| 52 | + vec4 p, s; |
| 53 | + |
| 54 | + p.set_xyz(((vec3(j) * ip.xyz()).fract() * 7.0).floor() * ip.z() - 1.0); |
| 55 | + p.w() = 1.5f - p.xyz().abs().dot(ones.xyz()); |
| 56 | + s = vec4(p.lessThan(vec4(0.0))); |
| 57 | + p.set_xyz(p.xyz() + (s.xyz() * 2.0 - 1.0) * s.w()); |
| 58 | + |
| 59 | + return p; |
| 60 | +} |
| 61 | + |
| 62 | +} // namespace detail |
| 63 | + |
| 64 | +[[nodiscard]] constexpr float simplex(vec2 v, const PermuteFactors& factors = {}) |
| 65 | +{ |
| 66 | + auto permute = [&](auto x) { return detail::permute(x, factors); }; |
| 67 | + |
| 68 | + constexpr vec4 C = vec4(0.211324865405187f, 0.366025403784439f, -0.577350269189626f, 0.024390243902439f); |
| 69 | + vec2 i = (v + v.dot(C.y())).floor(); |
| 70 | + vec2 x0 = v - i + i.dot(C.x()); |
| 71 | + vec2 i1 = x0.x() > x0.y() ? vec2(1.0f, 0.0f) : vec2(0.0f, 1.0f); |
| 72 | + vec4 x12 = x0.swizzle<0, 1, 0, 1>() + C.swizzle<0, 0, 2, 2>(); |
| 73 | + x12.set_xy(x12.xy() - i1); |
| 74 | + i = i.mod(289.0f); |
| 75 | + vec3 p = permute(permute(i.y() + vec3(0.0f, i1.y(), 1.0f)) + i.x() + vec3(0.0f, i1.x(), 1.0f)); |
| 76 | + vec3 m = (0.5f - vec3(x0.sqrdot(), x12.xy().sqrdot(), x12.zw().sqrdot())).max(0.0f); |
| 77 | + m *= m * m * m; |
| 78 | + vec3 x = 2.0f * (p * C.w()).fract() - 1.0f; |
| 79 | + vec3 h = x.abs() - 0.5f; |
| 80 | + vec3 ox = (x + 0.5f).floor(); |
| 81 | + vec3 a0 = x - ox; |
| 82 | + m *= detail::taylorInvSqrt(a0 * a0 + h * h); |
| 83 | + vec3 g; |
| 84 | + g.x() = a0.x() * x0.x() + h.x() * x0.y(); |
| 85 | + g.set_yz(a0.yz() * x12.xz() + h.yz() * x12.yw()); |
| 86 | + return 130.0f * m.dot(g); |
| 87 | +} |
| 88 | + |
| 89 | +[[nodiscard]] constexpr float simplex(vec3 v, const PermuteFactors& factors = {}) |
| 90 | +{ |
| 91 | + auto permute = [&](auto x) { return detail::permute(x, factors); }; |
| 92 | + |
| 93 | + constexpr vec2 C = vec2(1.0f / 6.0f, 1.0f / 3.0f); |
| 94 | + constexpr vec4 D = vec4(0.0f, 0.5f, 1.0f, 2.0f); |
| 95 | + |
| 96 | + vec3 i = (v + v.dot(C.y())).floor(); |
| 97 | + vec3 x0 = v - i + i.dot(C.x()); |
| 98 | + |
| 99 | + // vec3 g = x0.yzx().step(x0); |
| 100 | + vec3 g = x0.swizzle<1, 2, 2>().step(x0.swizzle<0, 1, 0>()); |
| 101 | + g.z() = 1.0f - g.z(); // Ugly fix |
| 102 | + |
| 103 | + vec3 l = 1.0f - g; |
| 104 | + vec3 i1 = g.min(l.zxy()); |
| 105 | + vec3 i2 = g.max(l.zxy()); |
| 106 | + |
| 107 | + vec3 x1 = x0 - i1 + 1.0f * C.x(); |
| 108 | + vec3 x2 = x0 - i2 + 2.0f * C.x(); |
| 109 | + vec3 x3 = x0 - 1.0f + 3.0f * C.x(); |
| 110 | + |
| 111 | + i = i.mod(289.0f); |
| 112 | + vec4 p = |
| 113 | + permute(permute(permute(i.z() + vec4(0.0f, i1.z(), i2.z(), 1.0f)) + i.y() + vec4(0.0f, i1.y(), i2.y(), 1.0f)) + |
| 114 | + i.x() + vec4(0.0f, i1.x(), i2.x(), 1.0f)); |
| 115 | + |
| 116 | + float n_ = 1.0f / 7.0f; |
| 117 | + vec3 ns = n_ * D.wyz() - D.swizzle<0, 2, 0>(); |
| 118 | + |
| 119 | + vec4 j = p - 49.0f * (p * ns.z() * ns.z()).floor(); |
| 120 | + |
| 121 | + vec4 x_ = (j * ns.z()).floor(); |
| 122 | + vec4 y_ = (j - 7.0f * x_).floor(); |
| 123 | + |
| 124 | + vec4 x = x_ * ns.x() + ns.y(); |
| 125 | + vec4 y = y_ * ns.x() + ns.y(); |
| 126 | + vec4 h = 1.0f - x.abs() - y.abs(); |
| 127 | + |
| 128 | + vec4 b0 = vec4(x.x(), x.y(), y.x(), y.y()); |
| 129 | + vec4 b1 = vec4(x.z(), x.w(), y.z(), y.w()); |
| 130 | + |
| 131 | + vec4 s0 = b0.floor() * 2.0f + 1.0f; |
| 132 | + vec4 s1 = b1.floor() * 2.0f + 1.0f; |
| 133 | + vec4 sh = -h.step(vec4(0.0f)); |
| 134 | + |
| 135 | + vec4 a0 = b0.xzyw() + s0.xzyw() * sh.swizzle<0, 0, 1, 1>(); |
| 136 | + vec4 a1 = b1.xzyw() + s1.xzyw() * sh.swizzle<2, 2, 3, 3>(); |
| 137 | + |
| 138 | + vec3 p0 = vec3(a0.x(), a0.y(), h.x()); |
| 139 | + vec3 p1 = vec3(a0.z(), a0.w(), h.y()); |
| 140 | + vec3 p2 = vec3(a1.x(), a1.y(), h.z()); |
| 141 | + vec3 p3 = vec3(a1.z(), a1.w(), h.w()); |
| 142 | + |
| 143 | + vec4 norm = detail::taylorInvSqrt(vec4(p0.sqrdot(), p1.sqrdot(), p2.sqrdot(), p3.sqrdot())); |
| 144 | + p0 *= norm.x(); |
| 145 | + p1 *= norm.y(); |
| 146 | + p2 *= norm.z(); |
| 147 | + p3 *= norm.w(); |
| 148 | + |
| 149 | + vec4 m = (0.6f - vec4(x0.sqrdot(), x1.sqrdot(), x2.sqrdot(), x3.sqrdot())).max(0.0f); |
| 150 | + m *= m * m * m; |
| 151 | + return 42.0f * m.dot(vec4(p0.dot(x0), p1.dot(x1), p2.dot(x2), p3.dot(x3))); |
| 152 | +} |
| 153 | + |
| 154 | +float simplex(vec4 v, const PermuteFactors& factors = {}) |
| 155 | +{ |
| 156 | + auto permute = [&](auto x) { return detail::permute(x, factors); }; |
| 157 | + |
| 158 | + constexpr vec2 C = vec2(0.138196601125010504f, 0.309016994374947451f); |
| 159 | + |
| 160 | + vec4 i = (v + v.dot(C.y())).floor(); |
| 161 | + vec4 x0 = v - i + i.dot(C.x()); |
| 162 | + |
| 163 | + vec4 i0; |
| 164 | + |
| 165 | + vec3 isX = x0.yzw().step(x0.x()); |
| 166 | + vec3 isYZ = x0.swizzle<2, 3, 3>().step(x0.swizzle<1, 1, 2>()); |
| 167 | + |
| 168 | + i0.x() = isX.x() + isX.y() + isX.z(); |
| 169 | + i0.set_yzw(1.0f - isX); |
| 170 | + |
| 171 | + i0.y() += isYZ.x() + isYZ.y(); |
| 172 | + i0.set_zw(i0.zw() + 1.0f - isYZ.xy()); |
| 173 | + |
| 174 | + i0.z() += isYZ.z(); |
| 175 | + i0.w() += 1.0f - isYZ.z(); |
| 176 | + |
| 177 | + vec4 i3 = i0.clamp(0.0f, 1.0f); |
| 178 | + vec4 i2 = (i0 - 1.0f).clamp(0.0f, 1.0f); |
| 179 | + vec4 i1 = (i0 - 2.0f).clamp(0.0f, 1.0f); |
| 180 | + |
| 181 | + vec4 x1 = x0 - i1 + 1.0f * C.x(); |
| 182 | + vec4 x2 = x0 - i2 + 2.0f * C.x(); |
| 183 | + vec4 x3 = x0 - i3 + 3.0f * C.x(); |
| 184 | + vec4 x4 = x0 - 1.0f + 4.0f * C.x(); |
| 185 | + |
| 186 | + i = i.mod(289.0f); |
| 187 | + float j0 = permute(permute(permute(permute(i.w()) + i.z()) + i.y()) + i.x()); |
| 188 | + vec4 j1 = permute(permute(permute(permute(i.w() + vec4(i1.w(), i2.w(), i3.w(), 1.0f)) + i.z() + |
| 189 | + vec4(i1.z(), i2.z(), i3.z(), 1.0f)) + |
| 190 | + i.y() + vec4(i1.y(), i2.y(), i3.y(), 1.0f)) + |
| 191 | + i.x() + vec4(i1.x(), i2.x(), i3.x(), 1.0f)); |
| 192 | + |
| 193 | + vec4 ip = vec4(1.0f / 294.0f, 1.0f / 49.0f, 1.0f / 7.0f, 0.0f); |
| 194 | + |
| 195 | + vec4 p0 = detail::grad4(j0, ip); |
| 196 | + vec4 p1 = detail::grad4(j1.x(), ip); |
| 197 | + vec4 p2 = detail::grad4(j1.y(), ip); |
| 198 | + vec4 p3 = detail::grad4(j1.z(), ip); |
| 199 | + vec4 p4 = detail::grad4(j1.w(), ip); |
| 200 | + |
| 201 | + vec4 norm = detail::taylorInvSqrt(vec4(p0.sqrdot(), p1.sqrdot(), p2.sqrdot(), p3.sqrdot())); |
| 202 | + p0 *= norm.x(); |
| 203 | + p1 *= norm.y(); |
| 204 | + p2 *= norm.z(); |
| 205 | + p3 *= norm.w(); |
| 206 | + p4 *= detail::taylorInvSqrt(p4.sqrdot()); |
| 207 | + |
| 208 | + vec3 m0 = (0.6f - vec3(x0.sqrdot(), x1.sqrdot(), x2.sqrdot())).max(0.0f); |
| 209 | + vec2 m1 = (0.6f - vec2(x3.sqrdot(), x4.sqrdot())).max(0.0f); |
| 210 | + m0 *= m0 * m0 * m0; |
| 211 | + m1 *= m1 * m1 * m1; |
| 212 | + return 49.0f * (m0.dot(vec3(p0.dot(x0), p1.dot(x1), p2.dot(x2))) + m1.dot(vec2(p3.dot(x3), p4.dot(x4)))); |
| 213 | +} |
| 214 | + |
| 215 | +} // namespace dang::math::noise |
0 commit comments