|
17 | 17 |
|
18 | 18 | // Std includes
|
19 | 19 | #include <algorithm>
|
| 20 | +#include <random> |
20 | 21 |
|
21 | 22 | // Our includes
|
22 | 23 | #include "EBGeometry_BoundingVolumes.hpp"
|
@@ -864,6 +865,231 @@ class RoundedBoxSDF : public SignedDistanceFunction<T>
|
864 | 865 | Vec3T<T> m_dimensions;
|
865 | 866 | };
|
866 | 867 |
|
| 868 | +/*! |
| 869 | + @brief Ken Perlins gradient noise function |
| 870 | +*/ |
| 871 | +template <class T> |
| 872 | +class PerlinSDF : public SignedDistanceFunction<T> |
| 873 | +{ |
| 874 | +public: |
| 875 | + /*! |
| 876 | + @brief Full constructor. |
| 877 | + @param[in] a_noiseAmplitude Noise amplitude |
| 878 | + @param[in] a_noiseFrequency Spatial noise frequency along the three Cartesian axes |
| 879 | + @param[in] a_noisePersistence Noise amplitude drop-off and frequency increase for octave noise. Should be < 1 |
| 880 | + @param[in] a_noiseOctaves Number of octaves. Should be > 0 |
| 881 | + */ |
| 882 | + PerlinSDF(const T a_noiseAmplitude, |
| 883 | + const Vec3T<T> a_noiseFrequency, |
| 884 | + const T a_noisePersistence, |
| 885 | + const unsigned int a_noiseOctaves) noexcept |
| 886 | + { |
| 887 | + m_noiseAmplitude = a_noiseAmplitude; |
| 888 | + m_noiseFrequency = a_noiseFrequency; |
| 889 | + m_noisePersistence = std::min(1.0, a_noisePersistence); |
| 890 | + m_noiseOctaves = std::max((unsigned int)1, a_noiseOctaves); |
| 891 | + |
| 892 | + // By default, use Ken Perlin's original permutation table |
| 893 | + for (int i = 0; i < 256; i++) { |
| 894 | + m_permutationTable[i] = s_permutationTable[i]; |
| 895 | + m_permutationTable[i + 256] = s_permutationTable[i]; |
| 896 | + } |
| 897 | + |
| 898 | +#if 1 // Development code |
| 899 | + std::random_device rd; |
| 900 | + std::mt19937 g(0); |
| 901 | + |
| 902 | + this->shuffle(g); |
| 903 | +#endif |
| 904 | + } |
| 905 | + |
| 906 | + /*! |
| 907 | + @brief Destructor (does nothing) |
| 908 | + */ |
| 909 | + virtual ~PerlinSDF() noexcept |
| 910 | + {} |
| 911 | + |
| 912 | + /*! |
| 913 | + @brief Signed distance function. |
| 914 | + @param[in] a_point Input point |
| 915 | + */ |
| 916 | + virtual T |
| 917 | + signedDistance(const Vec3T<T>& a_point) const noexcept override |
| 918 | + { |
| 919 | + T ret = 0.0; |
| 920 | + |
| 921 | + Vec3T<T> curFreq = m_noiseFrequency; |
| 922 | + T curAmp = 1.0; |
| 923 | + |
| 924 | + for (unsigned int curOctave = 0; curOctave < m_noiseOctaves; curOctave++) { |
| 925 | + ret += this->noise(a_point * curFreq) * curAmp; |
| 926 | + |
| 927 | + curFreq = curFreq / m_noisePersistence; |
| 928 | + curAmp = curAmp * m_noisePersistence; |
| 929 | + } |
| 930 | + |
| 931 | + return ret * m_noiseAmplitude; |
| 932 | + }; |
| 933 | + |
| 934 | + /*! |
| 935 | + @brief Shuffle the permutation with the input RNG. |
| 936 | + @details URNG should be a uniform random number generator, e.g. |
| 937 | + @param[in] g Uniform random number generator (e.g., std::mt19937) |
| 938 | + @note When using parallel calculations it is exceptionally important that the input RNG is the same across all threads/ranks. Otherwise, the |
| 939 | + user must manually ensure that the permutation table is the same. Failure to do so implies that each thread/rank generates it's own gradient noise |
| 940 | + and there is correspondingly no single geometry. |
| 941 | + */ |
| 942 | + template <class URNG> |
| 943 | + void |
| 944 | + shuffle(URNG& g) noexcept |
| 945 | + { |
| 946 | + |
| 947 | + for (unsigned int i = 0; i < 256; i++) { |
| 948 | + m_permutationTable[i] = i; |
| 949 | + } |
| 950 | + |
| 951 | + std::shuffle(m_permutationTable.begin(), m_permutationTable.begin() + 256, g); |
| 952 | + |
| 953 | + for (int i = 0; i < 256; i++) { |
| 954 | + m_permutationTable[i + 256] = m_permutationTable[i]; |
| 955 | + } |
| 956 | + } |
| 957 | + |
| 958 | + /*! |
| 959 | + @brief Get the internal permutation table |
| 960 | + @return m_permutationTable. |
| 961 | + */ |
| 962 | + std::array<int, 512>& |
| 963 | + getPermutationTable() noexcept |
| 964 | + { |
| 965 | + return m_permutationTable; |
| 966 | + } |
| 967 | + |
| 968 | +protected: |
| 969 | + /*! |
| 970 | + @brief Ken Perlin's original permutation array |
| 971 | + */ |
| 972 | + constexpr static std::array<int, 256> s_permutationTable = { |
| 973 | + 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, |
| 974 | + 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, |
| 975 | + 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, |
| 976 | + 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, |
| 977 | + 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, |
| 978 | + 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, |
| 979 | + 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, |
| 980 | + 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, |
| 981 | + 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, 34, |
| 982 | + 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, |
| 983 | + 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, |
| 984 | + 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180}; |
| 985 | + |
| 986 | + /*! |
| 987 | + @brief Noise frequency |
| 988 | + */ |
| 989 | + Vec3T<T> m_noiseFrequency; |
| 990 | + |
| 991 | + /*! |
| 992 | + @brief Noise amplitude |
| 993 | + */ |
| 994 | + T m_noiseAmplitude; |
| 995 | + |
| 996 | + /*! |
| 997 | + @brief Noise persistence |
| 998 | + */ |
| 999 | + T m_noisePersistence; |
| 1000 | + |
| 1001 | + /*! |
| 1002 | + @brief Permutation table |
| 1003 | + */ |
| 1004 | + std::array<T, 512> m_permutationTable; |
| 1005 | + |
| 1006 | + /*! |
| 1007 | + @brief Number of noise octaves |
| 1008 | + */ |
| 1009 | + unsigned int m_noiseOctaves; |
| 1010 | + |
| 1011 | + /*! |
| 1012 | + @brief Ken Perlin's lerp function |
| 1013 | + @param[in] t Input parameter |
| 1014 | + @param[in] a Input parameter |
| 1015 | + @param[in] b Input parameter |
| 1016 | + */ |
| 1017 | + virtual T |
| 1018 | + lerp(const T t, const T a, const T b) const noexcept |
| 1019 | + { |
| 1020 | + return a + t * (b - a); |
| 1021 | + }; |
| 1022 | + |
| 1023 | + /*! |
| 1024 | + @brief Ken Perlin's fade function |
| 1025 | + @param[in] t Input parameter |
| 1026 | + */ |
| 1027 | + virtual T |
| 1028 | + fade(const T t) const noexcept |
| 1029 | + { |
| 1030 | + return t * t * t * (t * (t * 6 - 15) + 10); |
| 1031 | + }; |
| 1032 | + |
| 1033 | + /*! |
| 1034 | + @brief Ken Perlins grad function |
| 1035 | + @param[in] hash Input parameter |
| 1036 | + @param[in] x Input parameter |
| 1037 | + @param[in] y Input parameter |
| 1038 | + @param[in] z Input parameter |
| 1039 | + */ |
| 1040 | + T |
| 1041 | + grad(const int hash, const T x, const T y, const T z) const noexcept |
| 1042 | + { |
| 1043 | + const int h = hash & 15; |
| 1044 | + const T u = h < 8 ? x : y; |
| 1045 | + const T v = h < 4 ? y : h == 12 || h == 14 ? x : y; |
| 1046 | + return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); |
| 1047 | + } |
| 1048 | + |
| 1049 | + /*! |
| 1050 | + @brief Octave noise function |
| 1051 | + @param[in] a_point Input point |
| 1052 | + */ |
| 1053 | + T |
| 1054 | + noise(const Vec3T<T>& a_point) const noexcept |
| 1055 | + { |
| 1056 | + // Lower cube corner |
| 1057 | + const int X = (int)std::floor(a_point[0]) & 255; |
| 1058 | + const int Y = (int)std::floor(a_point[1]) & 255; |
| 1059 | + const int Z = (int)std::floor(a_point[2]) & 255; |
| 1060 | + |
| 1061 | + // Relative distance wrt lower cube corner |
| 1062 | + const double x = a_point[0] - std::floor(a_point[0]); |
| 1063 | + const double y = a_point[1] - std::floor(a_point[1]); |
| 1064 | + const double z = a_point[2] - std::floor(a_point[2]); |
| 1065 | + |
| 1066 | + // Fade curves |
| 1067 | + const double u = fade(x); |
| 1068 | + const double v = fade(y); |
| 1069 | + const double w = fade(z); |
| 1070 | + |
| 1071 | + // Hash coordinates of 8 cube corners |
| 1072 | + const int A = m_permutationTable[X] + Y; |
| 1073 | + const int AA = m_permutationTable[A] + Z; |
| 1074 | + const int AB = m_permutationTable[A + 1] + Z; |
| 1075 | + const int B = m_permutationTable[X + 1] + Y; |
| 1076 | + const int BA = m_permutationTable[B] + Z; |
| 1077 | + const int BB = m_permutationTable[B + 1] + Z; |
| 1078 | + |
| 1079 | + // Add blended results from 8 corners of cube |
| 1080 | + return lerp( |
| 1081 | + w, |
| 1082 | + lerp(v, |
| 1083 | + lerp(u, grad(m_permutationTable[AA], x, y, z), grad(m_permutationTable[BA], x - 1, y, z)), |
| 1084 | + lerp(u, grad(m_permutationTable[AB], x, y - 1, z), grad(m_permutationTable[BB], x - 1, y - 1, z))), |
| 1085 | + lerp(v, |
| 1086 | + lerp(u, grad(m_permutationTable[AA + 1], x, y, z - 1), grad(m_permutationTable[BA + 1], x - 1, y, z - 1)), |
| 1087 | + lerp(u, |
| 1088 | + grad(m_permutationTable[AB + 1], x, y - 1, z - 1), |
| 1089 | + grad(m_permutationTable[BB + 1], x - 1, y - 1, z - 1)))); |
| 1090 | + }; |
| 1091 | +}; |
| 1092 | + |
867 | 1093 | #include "EBGeometry_NamespaceFooter.hpp"
|
868 | 1094 |
|
869 | 1095 | #endif
|
0 commit comments