diff --git a/core/include/jiminy/core/utilities/random.hxx b/core/include/jiminy/core/utilities/random.hxx index 0a04a9ef1..1e2541c3e 100644 --- a/core/include/jiminy/core/utilities/random.hxx +++ b/core/include/jiminy/core/utilities/random.hxx @@ -9,7 +9,7 @@ namespace jiminy { static inline constexpr double PERLIN_NOISE_PERSISTENCE{1.50}; - static inline constexpr double PERLIN_NOISE_LACUNARITY{1.15}; + static inline constexpr double PERLIN_NOISE_LACUNARITY{0.85}; // ***************************** Uniform random bit generators ***************************** // @@ -230,8 +230,7 @@ namespace jiminy { JIMINY_THROW(std::invalid_argument, "'wavelength' must be strictly larger than 0.0."); } - auto gen = uniform_random_bit_generator_ref{std::random_device{}}; - shift_ = uniform(N, 1, gen).cast(); + reset(std::random_device{}); } template class DerivedPerlinNoiseOctave, unsigned int N> @@ -297,7 +296,7 @@ namespace jiminy { VectorN knot; VectorN delta; - const auto derived = static_cast &>(*this); + const auto & derived = static_cast &>(*this); for (uint32_t k = 0; k < (1U << N); k++) { // Mapping from index to knot @@ -398,7 +397,7 @@ namespace jiminy RandomPerlinNoiseOctave::RandomPerlinNoiseOctave(double wavelength) : AbstractPerlinNoiseOctave(wavelength) { - seed_ = std::random_device{}(); + reset(std::random_device{}); } template @@ -408,7 +407,7 @@ namespace jiminy // Call base implementation AbstractPerlinNoiseOctave::reset(g); - // Sample new random seed for MurmurHash + // Sample new random seed seed_ = g(); } @@ -502,12 +501,6 @@ namespace jiminy reset(std::random_device{}); } - template - double PeriodicPerlinNoiseOctave::getPeriod() const noexcept - { - return period_; - } - template void PeriodicPerlinNoiseOctave::reset( const uniform_random_bit_generator_ref & g) noexcept @@ -516,28 +509,25 @@ namespace jiminy AbstractPerlinNoiseOctave::reset(g); // Re-initialize the pre-computed hash table - std::generate( - grads_.begin(), - grads_.end(), - [&g]() -> VectorN + for (auto & grad : grads_) + { + if constexpr (N == 1) { - if constexpr (N == 1) - { - return VectorN{uniform(g, -1.0F, 1.0F)}; - } - else if constexpr (N == 2) - { - const double theta = 2 * M_PI * uniform(g); - const float radius = std::sqrt(uniform(g)); - return VectorN{radius * std::cos(theta), radius * std::sin(theta)}; - } - else - { - const VectorN dir = normal(N, 1, g).cast().normalized(); - const double radius = std::pow(uniform(g), 1.0 / N); - return radius * dir; - } - }); + grad = VectorN{uniform(g, -1.0F, 1.0F)}; + } + else if constexpr (N == 2) + { + const double theta = 2 * M_PI * uniform(g); + const float radius = std::sqrt(uniform(g)); + grad = VectorN{radius * std::cos(theta), radius * std::sin(theta)}; + } + else + { + const VectorN dir = normal(N, 1, g).cast().normalized(); + const double radius = std::pow(uniform(g), 1.0 / N); + grad = radius * dir; + } + } } template @@ -562,6 +552,12 @@ namespace jiminy return grads_[index]; } + template + double PeriodicPerlinNoiseOctave::getPeriod() const noexcept + { + return period_; + } + template class DerivedPerlinNoiseOctave, unsigned int N> AbstractPerlinProcess::AbstractPerlinProcess( std::vector && octaveScalePairs) noexcept : @@ -643,19 +639,26 @@ namespace jiminy static std::vector, const double>> buildPerlinNoiseOctaves(double wavelength, std::size_t numOctaves, ExtraArgs &&... args) { + // Make sure that at least one octave has been requested + if (numOctaves < 1) + { + JIMINY_THROW(std::invalid_argument, "'numOctaves' must at least 1."); + } + + // Make sure that wavelength of all the octaves is consistent with period if application if constexpr (std::is_base_of_v, DerivedPerlinNoiseOctave>) { const double period = std::get<0>(std::tuple{std::forward(args)...}); - const double wavelengthMax = - std::pow(PERLIN_NOISE_LACUNARITY, numOctaves) * wavelength; - if (period < wavelengthMax) + const double wavelengthFinal = + wavelength / std::pow(PERLIN_NOISE_LACUNARITY, numOctaves - 1); + if (period < std::max(wavelength, wavelengthFinal)) { JIMINY_THROW(std::invalid_argument, - "'period' must be larger than (", + "'period' must be larger than the wavelength of all the octaves (", + std::max(wavelength, wavelengthFinal), + "), ie 'wavelength' / ", PERLIN_NOISE_LACUNARITY, - "^'numOctaves') * 'wavelength' (ie. ", - wavelengthMax, - ")."); + "^i for i in [1, ..., 'numOctaves']."); } } @@ -665,7 +668,7 @@ namespace jiminy for (std::size_t i = 0; i < numOctaves; ++i) { octaveScalePairs.emplace_back(DerivedPerlinNoiseOctave(wavelength, args...), scale); - wavelength *= PERLIN_NOISE_LACUNARITY; + wavelength /= PERLIN_NOISE_LACUNARITY; scale *= PERLIN_NOISE_PERSISTENCE; } return octaveScalePairs; diff --git a/core/src/utilities/geometry.cc b/core/src/utilities/geometry.cc index f06dd910a..4832a2147 100644 --- a/core/src/utilities/geometry.cc +++ b/core/src/utilities/geometry.cc @@ -902,7 +902,7 @@ namespace jiminy const auto grad = fun.grad(pos); // Compute the inverse of the normal's Euclidean norm - const double normInv = 1.0 / grad.norm(); + const double normInv = 1.0 / std::sqrt(1.0 + grad.squaredNorm()); // Update normal vector normal.value() << -normInv * grad.template head<2>(), normInv;