Browse Source

Simplify noise function signatures and provide default parameter values

master
C. J. Howard 2 years ago
parent
commit
94d9142ebf
8 changed files with 159 additions and 108 deletions
  1. +17
    -22
      src/game/load.cpp
  2. +1
    -0
      src/math/hash/hash.hpp
  3. +68
    -0
      src/math/hash/make-uint.hpp
  4. +11
    -37
      src/math/hash/pcg.hpp
  5. +6
    -4
      src/math/noise/fbm.hpp
  6. +14
    -8
      src/math/noise/simplex.hpp
  7. +36
    -37
      src/math/noise/voronoi.hpp
  8. +6
    -0
      src/math/vector.hpp

+ 17
- 22
src/game/load.cpp View File

@ -48,6 +48,7 @@ void biome(game::context& ctx, const std::filesystem::path& path)
{ {
ctx.logger->push_task("Loading biome from \"" + path.string() + "\""); ctx.logger->push_task("Loading biome from \"" + path.string() + "\"");
/*
image img; image img;
img.format(1, 1); img.format(1, 1);
img.resize(1024, 1024); img.resize(1024, 1024);
@ -113,7 +114,7 @@ void biome(game::context& ctx, const std::filesystem::path& path)
// f2_displacement, // f2_displacement,
// f2_id // f2_id
edge_sqr_distance edge_sqr_distance
] = math::noise::voronoi::f1_edge<float, 1, std::uint32_t>({position[0]}, 1.0f, {0.0f}, &math::hash::pcg);
] = math::noise::voronoi::f1_edge<float, 2>(position);
float f1_distance = std::sqrt(f1_sqr_distance); float f1_distance = std::sqrt(f1_sqr_distance);
//float f2_distance = std::sqrt(f2_sqr_distance); //float f2_distance = std::sqrt(f2_sqr_distance);
@ -126,7 +127,7 @@ void biome(game::context& ctx, const std::filesystem::path& path)
stbi_flip_vertically_on_write(1); stbi_flip_vertically_on_write(1);
stbi_write_png((ctx.config_path / "gallery" / "noise.png").string().c_str(), img.get_width(), img.get_height(), img.get_channel_count(), img.data(), img.get_width() * img.get_channel_count()); stbi_write_png((ctx.config_path / "gallery" / "noise.png").string().c_str(), img.get_width(), img.get_height(), img.get_channel_count(), img.data(), img.get_width() * img.get_channel_count());
*/
try try
{ {
@ -194,38 +195,32 @@ void biome(game::context& ctx, const std::filesystem::path& path)
( (
[](float x, float z) -> float [](float x, float z) -> float
{ {
float angle = math::radians(30.0f);
float c = std::cos(angle);
float s = std::sin(angle);
x = x * c - z * s;
z = x * s + z * c;
float frequency = 0.01f; float frequency = 0.01f;
std::size_t octaves = 4; std::size_t octaves = 4;
float lacunarity = 3.0f; float lacunarity = 3.0f;
float gain = 0.5f; float gain = 0.5f;
auto noise = static_cast<float(*)(const math::vector<float, 2>&, decltype(hash))>(math::noise::simplex);
auto hash = static_cast<math::vector<std::uint32_t, 2>(*)(const math::vector<float, 2>&)>(math::hash::pcg);
float2 position = float2{x, z} * frequency; float2 position = float2{x, z} * frequency;
/*
float n = math::noise::fbm
float fbm = math::noise::fbm
( (
position, position,
octaves, octaves,
lacunarity, lacunarity,
gain,
noise,
hash
gain
); );
*/
//float n = math::noise::voronoi::f1<float, std::uint32_t>(position, 1.0f, &math::noise::hash::pcg3d_3)[0];
float n = 0.0f;
return 10.0f * n;
auto
[
f1_sqr_distance,
f1_displacement,
f1_id
] = math::noise::voronoi::f1(position);
float f1_distance = std::sqrt(f1_sqr_distance);
float y = f1_distance * 5.0f + fbm * 0.5f;
return y;
} }
); );

+ 1
- 0
src/math/hash/hash.hpp View File

@ -27,6 +27,7 @@ namespace hash {}
} // namespace math } // namespace math
#include "math/hash/make-uint.hpp"
#include "math/hash/pcg.hpp" #include "math/hash/pcg.hpp"
#endif // ANTKEEPER_MATH_HASH_HPP #endif // ANTKEEPER_MATH_HASH_HPP

+ 68
- 0
src/math/hash/make-uint.hpp View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2021 Christopher J. Howard
*
* This file is part of Antkeeper source code.
*
* Antkeeper source code is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Antkeeper source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_MATH_HASH_MAKE_UINT_HPP
#define ANTKEEPER_MATH_HASH_MAKE_UINT_HPP
#include <cstdint>
#include <type_traits>
namespace math {
namespace hash {
/**
* Provides an unsigned integer type of equivalent size to type @p T.
*/
template <class T>
struct make_uint
{
static_assert(std::is_integral<T>::value);
/// Unsigned integer type of equivalent size to type @p T.
typedef typename std::make_unsigned<T>::type type;
};
/// Provides an unsigned integer type of equivalent size to `float`.
template<>
struct make_uint<float>
{
static_assert(sizeof(float) == sizeof(std::uint32_t));
/// Unsigned integer type of equivalent size to `float`.
typedef std::uint32_t type;
};
/// Provides an unsigned integer type of equivalent size to `double`.
template<>
struct make_uint<double>
{
static_assert(sizeof(double) == sizeof(std::uint64_t));
/// Unsigned integer type of equivalent size to `double`.
typedef std::uint64_t type;
};
/// Helper type for make_uint.
template <class T>
using make_uint_t = typename make_uint<T>::type;
} // namespace hash
} // namespace math
#endif // ANTKEEPER_MATH_HASH_MAKE_UINT_HPP

+ 11
- 37
src/math/hash/pcg.hpp View File

@ -21,42 +21,13 @@
#define ANTKEEPER_MATH_HASH_PCG_HPP #define ANTKEEPER_MATH_HASH_PCG_HPP
#include "math/vector.hpp" #include "math/vector.hpp"
#include "math/hash/make-uint.hpp"
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
namespace math { namespace math {
namespace hash { namespace hash {
/**
* Provides an unsigned integer type of equivalent size to type @p T.
*/
template <class T>
struct pcg_make_uint
{
static_assert(std::is_integral<T>::value);
/// Unsigned integer type of equivalent size to type @p T.
typedef typename std::make_unsigned<T>::type type;
};
/// Provides an unsigned integer type of equivalent to `float`.
template<>
struct pcg_make_uint<float>
{
typedef std::uint32_t type;
};
/// Provides an unsigned integer type of equivalent to `double`.
template<>
struct pcg_make_uint<double>
{
typedef std::uint64_t type;
};
/// Helper type for pcg_make_uint.
template <class T>
using pcg_make_uint_t = typename pcg_make_uint<T>::type;
/// @private /// @private
template <class T> template <class T>
constexpr T pcg_multiplier = 0; constexpr T pcg_multiplier = 0;
@ -197,7 +168,10 @@ constexpr vector pcg_uvec4(vector x) noexcept
* *
* @param x Input value. * @param x Input value.
* *
* @return Pseudorandom output value.
* @return Unsigned pseudorandom output value.
*
* @warning Floating point and signed input values will be converted to unsigned integers via `static_cast`.
* @warning Vectors with more than 4 elements are not supported.
* *
* @see https://en.wikipedia.org/wiki/Permuted_congruential_generator * @see https://en.wikipedia.org/wiki/Permuted_congruential_generator
* @see O'Neill, M.E. (2014). PCG : A Family of Simple Fast Space-Efficient Statistically Good Algorithms for Random Number Generation. * @see O'Neill, M.E. (2014). PCG : A Family of Simple Fast Space-Efficient Statistically Good Algorithms for Random Number Generation.
@ -255,18 +229,18 @@ inline constexpr std::uint64_t pcg(double x) noexcept
} }
template <class T, std::size_t N> template <class T, std::size_t N>
inline constexpr vector<pcg_make_uint_t<T>, N> pcg(const vector<T, N>& x) noexcept
inline constexpr vector<make_uint_t<T>, N> pcg(const vector<T, N>& x) noexcept
{ {
static_assert(N > 0 && N < 5, "Dimension not supported by PCG hash.");
static_assert(N > 0 && N < 5, "PCG hash only supports vectors with 1-4 elements.");
if constexpr (N == 1) if constexpr (N == 1)
return pcg_uvec1<pcg_make_uint_t<T>>(vector<pcg_make_uint_t<T>, N>(x));
return pcg_uvec1<make_uint_t<T>>(vector<make_uint_t<T>, N>(x));
else if constexpr (N == 2) else if constexpr (N == 2)
return pcg_uvec2<pcg_make_uint_t<T>>(vector<pcg_make_uint_t<T>, N>(x));
return pcg_uvec2<make_uint_t<T>>(vector<make_uint_t<T>, N>(x));
else if constexpr (N == 3) else if constexpr (N == 3)
return pcg_uvec3<pcg_make_uint_t<T>>(vector<pcg_make_uint_t<T>, N>(x));
return pcg_uvec3<make_uint_t<T>>(vector<make_uint_t<T>, N>(x));
else else
return pcg_uvec4<pcg_make_uint_t<T>>(vector<pcg_make_uint_t<T>, N>(x));
return pcg_uvec4<make_uint_t<T>>(vector<make_uint_t<T>, N>(x));
} }
/// @} /// @}

+ 6
- 4
src/math/noise/fbm.hpp View File

@ -20,6 +20,9 @@
#ifndef ANTKEEPER_MATH_NOISE_FBM_HPP #ifndef ANTKEEPER_MATH_NOISE_FBM_HPP
#define ANTKEEPER_MATH_NOISE_FBM_HPP #define ANTKEEPER_MATH_NOISE_FBM_HPP
#include "math/hash/make-uint.hpp"
#include "math/hash/pcg.hpp"
#include "math/noise/simplex.hpp"
#include "math/vector.hpp" #include "math/vector.hpp"
#include <cstdint> #include <cstdint>
@ -31,7 +34,6 @@ namespace noise {
* *
* @tparam T Real type. * @tparam T Real type.
* @tparam N Number of dimensions. * @tparam N Number of dimensions.
* @tparam U Hash function return type.
* *
* @param x n-dimensional input value. * @param x n-dimensional input value.
* @param octaves Number of octaves. * @param octaves Number of octaves.
@ -41,15 +43,15 @@ namespace noise {
* @param hash Hash function. * @param hash Hash function.
* *
*/ */
template <class T, std::size_t N, class U>
template <class T, std::size_t N>
T fbm T fbm
( (
vector<T, N> x, vector<T, N> x,
std::size_t octaves, std::size_t octaves,
T lacunarity, T lacunarity,
T gain, T gain,
T (*noise)(const vector<T, N>&, vector<U, N> (*)(const vector<T, N>&)),
vector<U, N> (*hash)(const vector<T, N>&)
T (*noise)(const vector<T, N>&, vector<hash::make_uint_t<T>, N> (*)(const vector<T, N>&)) = &simplex<T, N>,
vector<hash::make_uint_t<T>, N> (*hash)(const vector<T, N>&) = &hash::pcg<T, N>
) )
{ {
T amplitude{1}; T amplitude{1};

+ 14
- 8
src/math/noise/simplex.hpp View File

@ -21,6 +21,8 @@
#define ANTKEEPER_MATH_NOISE_SIMPLEX_HPP #define ANTKEEPER_MATH_NOISE_SIMPLEX_HPP
#include "math/vector.hpp" #include "math/vector.hpp"
#include "math/hash/make-uint.hpp"
#include "math/hash/pcg.hpp"
#include <algorithm> #include <algorithm>
#include <utility> #include <utility>
@ -109,8 +111,12 @@ constexpr auto simplex_edges = make_simplex_edges(std::make_index_sequence
* @see https://briansharpe.wordpress.com/2011/11/14/two-useful-interpolation-functions-for-noise-development/ * @see https://briansharpe.wordpress.com/2011/11/14/two-useful-interpolation-functions-for-noise-development/
* @see https://math.stackexchange.com/questions/474638/radius-and-amplitude-of-kernel-for-simplex-noise/1901116 * @see https://math.stackexchange.com/questions/474638/radius-and-amplitude-of-kernel-for-simplex-noise/1901116
*/ */
template <class T, std::size_t N, class U>
T simplex(const vector<T, N>& x, vector<U, N> (*hash)(const vector<T, N>&))
template <class T, std::size_t N>
T simplex
(
const vector<T, N>& x,
vector<hash::make_uint_t<T>, N> (*hash)(const vector<T, N>&) = &hash::pcg<T, N>
)
{ {
// Skewing (F) and unskewing (G) factors // Skewing (F) and unskewing (G) factors
static const T f = (std::sqrt(static_cast<T>(N + 1)) - T{1}) / static_cast<T>(N); static const T f = (std::sqrt(static_cast<T>(N + 1)) - T{1}) / static_cast<T>(N);
@ -137,13 +143,13 @@ T simplex(const vector& x, vector (*hash)(const vector&))
static const T corner_normalization = T{1} / ((static_cast<T>(N) / std::sqrt(static_cast<T>(N + 1))) * falloff(static_cast<T>(N) / (T{4} * static_cast<T>(N + 1)))); static const T corner_normalization = T{1} / ((static_cast<T>(N) / std::sqrt(static_cast<T>(N + 1))) * falloff(static_cast<T>(N) / (T{4} * static_cast<T>(N + 1))));
// Adjust normalization factor for difference in length between corner gradient vectors and edge gradient vectors // Adjust normalization factor for difference in length between corner gradient vectors and edge gradient vectors
static const T edge_normalization = corner_normalization * (std::sqrt(static_cast<T>(N)) / math::length(simplex_edges<T, N>[0]));
static const T edge_normalization = corner_normalization * (std::sqrt(static_cast<T>(N)) / length(simplex_edges<T, N>[0]));
// Skew input position to get the origin vertex of the unit hypercube cell to which they belong // Skew input position to get the origin vertex of the unit hypercube cell to which they belong
const vector<T, N> origin_vertex = math::floor(x + math::sum(x) * f);
const vector<T, N> origin_vertex = floor(x + sum(x) * f);
// Displacement vector from origin vertex position to input position // Displacement vector from origin vertex position to input position
const vector<T, N> dx = x - origin_vertex + math::sum(origin_vertex) * g;
const vector<T, N> dx = x - origin_vertex + sum(origin_vertex) * g;
// Find axis traversal order // Find axis traversal order
vector<std::size_t, N> axis_order; vector<std::size_t, N> axis_order;
@ -170,13 +176,13 @@ T simplex(const vector& x, vector (*hash)(const vector&))
const vector<T, N> d = dx - (current_vertex - origin_vertex) + g * static_cast<T>(i); const vector<T, N> d = dx - (current_vertex - origin_vertex) + g * static_cast<T>(i);
// Calculate falloff // Calculate falloff
T t = falloff(math::length_squared(d));
T t = falloff(length_squared(d));
if (t > T{0}) if (t > T{0})
{ {
const auto gradient_index = hash(current_vertex)[0] % simplex_edges<T, N>.size();
const hash::make_uint_t<T> gradient_index = hash(current_vertex)[0] % simplex_edges<T, N>.size();
const vector<T, N>& gradient = simplex_edges<T, N>[gradient_index]; const vector<T, N>& gradient = simplex_edges<T, N>[gradient_index];
n += math::dot(d, gradient) * t;
n += dot(d, gradient) * t;
} }
} }

+ 36
- 37
src/math/noise/voronoi.hpp View File

@ -21,6 +21,8 @@
#define ANTKEEPER_MATH_NOISE_VORONOI_HPP #define ANTKEEPER_MATH_NOISE_VORONOI_HPP
#include "math/vector.hpp" #include "math/vector.hpp"
#include "math/hash/make-uint.hpp"
#include "math/hash/pcg.hpp"
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cmath> #include <cmath>
@ -96,7 +98,6 @@ constexpr auto kernel = generate_kernel(std::make_index_sequence
* *
* @tparam T Real type. * @tparam T Real type.
* @tparam N Number of dimensions. * @tparam N Number of dimensions.
* @tparam U Hash function return type.
* *
* @param position Input position. * @param position Input position.
* @param randomness Degree of randomness, on `[0, 1]`. * @param randomness Degree of randomness, on `[0, 1]`.
@ -105,7 +106,7 @@ constexpr auto kernel = generate_kernel(std::make_index_sequence
* *
* @return Tuple containing the square Euclidean distance from @p position to the F1 cell, the displacement vector from the input position to the F1 cell center, and a hash value indicating the ID of the F1 cell. * @return Tuple containing the square Euclidean distance from @p position to the F1 cell, the displacement vector from the input position to the F1 cell center, and a hash value indicating the ID of the F1 cell.
*/ */
template <class T, std::size_t N, class U>
template <class T, std::size_t N>
std::tuple std::tuple
< <
// F1 square distance to center // F1 square distance to center
@ -115,27 +116,27 @@ std::tuple
vector<T, N>, vector<T, N>,
// F1 hash // F1 hash
U
hash::make_uint_t<T>
> >
f1 f1
( (
const vector<T, N>& position, const vector<T, N>& position,
T randomness,
const vector<T, N>& tiling,
vector<U, N> (*hash)(const vector<T, N>&)
T randomness = T{1},
const vector<T, N>& tiling = vector<T, N>::zero(),
vector<hash::make_uint_t<T>, N> (*hash)(const vector<T, N>&) = &hash::pcg<T, N>
) )
{ {
// Calculate factor which scales hash value onto `[0, 1]`, modulated by desired randomness // Calculate factor which scales hash value onto `[0, 1]`, modulated by desired randomness
T hash_scale = (T{1} / static_cast<T>(std::numeric_limits<U>::max())) * randomness;
T hash_scale = (T{1} / static_cast<T>(std::numeric_limits<hash::make_uint_t<T>>::max())) * randomness;
// Get integer and fractional parts // Get integer and fractional parts
vector<T, N> position_i = math::floor(position - T{1.5});
vector<T, N> position_i = floor(position - T{1.5});
vector<T, N> position_f = position - position_i; vector<T, N> position_f = position - position_i;
// Find the F1 cell // Find the F1 cell
T f1_sqr_distance = std::numeric_limits<T>::infinity(); T f1_sqr_distance = std::numeric_limits<T>::infinity();
vector<T, N> f1_displacement; vector<T, N> f1_displacement;
U f1_hash;
hash::make_uint_t<T> f1_hash;
for (std::size_t i = 0; i < kernel_size<N>; ++i) for (std::size_t i = 0; i < kernel_size<N>; ++i)
{ {
// Get kernel offset for current cell // Get kernel offset for current cell
@ -150,7 +151,7 @@ f1
} }
// Calculate hash values for the hash position // Calculate hash values for the hash position
vector<U, N> hash_i = hash(hash_position);
vector<hash::make_uint_t<T>, N> hash_i = hash(hash_position);
// Convert hash values to pseudorandom fractional offset // Convert hash values to pseudorandom fractional offset
vector<T, N> offset_f = vector<T, N>(hash_i) * hash_scale; vector<T, N> offset_f = vector<T, N>(hash_i) * hash_scale;
@ -159,7 +160,7 @@ f1
vector<T, N> displacement = (offset_i + offset_f) - position_f; vector<T, N> displacement = (offset_i + offset_f) - position_f;
// Calculate square distance to the current cell center // Calculate square distance to the current cell center
T sqr_distance = math::length_squared(displacement);
T sqr_distance = length_squared(displacement);
// Update F1 cell // Update F1 cell
if (sqr_distance < f1_sqr_distance) if (sqr_distance < f1_sqr_distance)
@ -183,7 +184,6 @@ f1
* *
* @tparam T Real type. * @tparam T Real type.
* @tparam N Number of dimensions. * @tparam N Number of dimensions.
* @tparam U Hash function return type.
* *
* @param position Input position. * @param position Input position.
* @param randomness Degree of randomness, on `[0, 1]`. * @param randomness Degree of randomness, on `[0, 1]`.
@ -192,7 +192,7 @@ f1
* *
* @return Tuple containing the square Euclidean distance from @p position to the F1 cell center, the displacement vector from the input position to the F1 cell center, a hash value indicating the ID of the F1 cell, and the square Euclidean distance from @p position to the nearest edge. * @return Tuple containing the square Euclidean distance from @p position to the F1 cell center, the displacement vector from the input position to the F1 cell center, a hash value indicating the ID of the F1 cell, and the square Euclidean distance from @p position to the nearest edge.
*/ */
template <class T, std::size_t N, class U>
template <class T, std::size_t N>
std::tuple std::tuple
< <
// F1 square distance to center // F1 square distance to center
@ -202,7 +202,7 @@ std::tuple
vector<T, N>, vector<T, N>,
// F1 hash // F1 hash
U,
hash::make_uint_t<T>,
// Edge square distance // Edge square distance
T T
@ -210,23 +210,23 @@ std::tuple
f1_edge f1_edge
( (
const vector<T, N>& position, const vector<T, N>& position,
T randomness,
const vector<T, N>& tiling,
vector<U, N> (*hash)(const vector<T, N>&)
T randomness = T{1},
const vector<T, N>& tiling = vector<T, N>::zero(),
vector<hash::make_uint_t<T>, N> (*hash)(const vector<T, N>&) = &hash::pcg<T, N>
) )
{ {
// Calculate factor which scales hash value onto `[0, 1]`, modulated by desired randomness // Calculate factor which scales hash value onto `[0, 1]`, modulated by desired randomness
T hash_scale = (T{1} / static_cast<T>(std::numeric_limits<U>::max())) * randomness;
T hash_scale = (T{1} / static_cast<T>(std::numeric_limits<hash::make_uint_t<T>>::max())) * randomness;
// Get integer and fractional parts // Get integer and fractional parts
vector<T, N> position_i = math::floor(position - T{1.5});
vector<T, N> position_i = floor(position - T{1.5});
vector<T, N> position_f = position - position_i; vector<T, N> position_f = position - position_i;
// Find F1 cell // Find F1 cell
T f1_sqr_distance_center = std::numeric_limits<T>::infinity(); T f1_sqr_distance_center = std::numeric_limits<T>::infinity();
vector<T, N> displacement_cache[kernel_size<N>]; vector<T, N> displacement_cache[kernel_size<N>];
std::size_t f1_i = 0; std::size_t f1_i = 0;
U f1_hash;
hash::make_uint_t<T> f1_hash;
for (std::size_t i = 0; i < kernel_size<N>; ++i) for (std::size_t i = 0; i < kernel_size<N>; ++i)
{ {
// Get kernel offset for current cell // Get kernel offset for current cell
@ -241,7 +241,7 @@ f1_edge
} }
// Calculate hash values for the hash position // Calculate hash values for the hash position
vector<U, N> hash_i = hash(hash_position);
vector<hash::make_uint_t<T>, N> hash_i = hash(hash_position);
// Convert hash values to pseudorandom fractional offset // Convert hash values to pseudorandom fractional offset
vector<T, N> offset_f = vector<T, N>(hash_i) * hash_scale; vector<T, N> offset_f = vector<T, N>(hash_i) * hash_scale;
@ -250,7 +250,7 @@ f1_edge
displacement_cache[i] = (offset_i + offset_f) - position_f; displacement_cache[i] = (offset_i + offset_f) - position_f;
// Calculate square distance to the current cell center // Calculate square distance to the current cell center
T sqr_distance = math::length_squared(displacement_cache[i]);
T sqr_distance = length_squared(displacement_cache[i]);
// Update F1 cell // Update F1 cell
if (sqr_distance < f1_sqr_distance_center) if (sqr_distance < f1_sqr_distance_center)
@ -279,10 +279,10 @@ f1_edge
const vector<T, N> midpoint = (f1_displacement + displacement) * T{0.5}; const vector<T, N> midpoint = (f1_displacement + displacement) * T{0.5};
// Calculate direction from the F1 cell to current cell // Calculate direction from the F1 cell to current cell
const vector<T, N> direction = math::normalize(displacement - f1_displacement);
const vector<T, N> direction = normalize(displacement - f1_displacement);
// Calculate square distance to the edge // Calculate square distance to the edge
const T sqr_distance = math::dot(midpoint, direction);
const T sqr_distance = dot(midpoint, direction);
// Update minimum edge distance if closer than the nearest edge // Update minimum edge distance if closer than the nearest edge
if (sqr_distance < edge_sqr_distance_edge) if (sqr_distance < edge_sqr_distance_edge)
@ -303,7 +303,6 @@ f1_edge
* *
* @tparam T Real type. * @tparam T Real type.
* @tparam N Number of dimensions. * @tparam N Number of dimensions.
* @tparam U Hash function return type.
* *
* @param position Input position. * @param position Input position.
* @param randomness Degree of randomness, on `[0, 1]`. * @param randomness Degree of randomness, on `[0, 1]`.
@ -312,7 +311,7 @@ f1_edge
* *
* @return Tuple containing the square Euclidean distances, displacement vectors from the input position to the cell centers, and hash values indicating the cell IDs, for both the F1 and F2 cells. * @return Tuple containing the square Euclidean distances, displacement vectors from the input position to the cell centers, and hash values indicating the cell IDs, for both the F1 and F2 cells.
*/ */
template <class T, std::size_t N, class U>
template <class T, std::size_t N>
std::tuple std::tuple
< <
// F1 square distance to center // F1 square distance to center
@ -322,7 +321,7 @@ std::tuple
vector<T, N>, vector<T, N>,
// F1 hash // F1 hash
U,
hash::make_uint_t<T>,
// F2 square distance to center // F2 square distance to center
T, T,
@ -331,30 +330,30 @@ std::tuple
vector<T, N>, vector<T, N>,
// F2 hash // F2 hash
U
hash::make_uint_t<T>
> >
f1_f2 f1_f2
( (
const vector<T, N>& position, const vector<T, N>& position,
T randomness,
const vector<T, N>& tiling,
vector<U, N> (*hash)(const vector<T, N>&)
T randomness = T{1},
const vector<T, N>& tiling = vector<T, N>::zero(),
vector<hash::make_uint_t<T>, N> (*hash)(const vector<T, N>&) = &hash::pcg<T, N>
) )
{ {
// Calculate factor which scales hash value onto `[0, 1]`, modulated by desired randomness // Calculate factor which scales hash value onto `[0, 1]`, modulated by desired randomness
T hash_scale = (T{1} / static_cast<T>(std::numeric_limits<U>::max())) * randomness;
T hash_scale = (T{1} / static_cast<T>(std::numeric_limits<hash::make_uint_t<T>>::max())) * randomness;
// Get integer and fractional parts // Get integer and fractional parts
vector<T, N> position_i = math::floor(position - T{1.5});
vector<T, N> position_i = floor(position - T{1.5});
vector<T, N> position_f = position - position_i; vector<T, N> position_f = position - position_i;
// Find the F1 and F2 cells // Find the F1 and F2 cells
T f1_sqr_distance_center = std::numeric_limits<T>::infinity(); T f1_sqr_distance_center = std::numeric_limits<T>::infinity();
vector<T, N> f1_displacement = {0, 0}; vector<T, N> f1_displacement = {0, 0};
U f1_hash = 0;
hash::make_uint_t<T> f1_hash = 0;
T f2_sqr_distance_center = std::numeric_limits<T>::infinity(); T f2_sqr_distance_center = std::numeric_limits<T>::infinity();
vector<T, N> f2_displacement = {0, 0}; vector<T, N> f2_displacement = {0, 0};
U f2_hash = 0;
hash::make_uint_t<T> f2_hash = 0;
for (std::size_t i = 0; i < kernel_size<N>; ++i) for (std::size_t i = 0; i < kernel_size<N>; ++i)
{ {
// Get kernel offset for current cell // Get kernel offset for current cell
@ -369,7 +368,7 @@ f1_f2
} }
// Calculate hash values for the hash position // Calculate hash values for the hash position
vector<U, N> hash_i = hash(hash_position);
vector<hash::make_uint_t<T>, N> hash_i = hash(hash_position);
// Convert hash values to pseudorandom fractional offset // Convert hash values to pseudorandom fractional offset
vector<T, N> offset_f = vector<T, N>(hash_i) * hash_scale; vector<T, N> offset_f = vector<T, N>(hash_i) * hash_scale;
@ -378,7 +377,7 @@ f1_f2
vector<T, N> displacement = (offset_i + offset_f) - position_f; vector<T, N> displacement = (offset_i + offset_f) - position_f;
// Calculate square distance to the current cell center // Calculate square distance to the current cell center
T sqr_distance = math::length_squared(displacement);
T sqr_distance = length_squared(displacement);
// Update F1 and F2 cells // Update F1 and F2 cells
if (sqr_distance < f1_sqr_distance_center) if (sqr_distance < f1_sqr_distance_center)

+ 6
- 0
src/math/vector.hpp View File

@ -254,6 +254,12 @@ struct vector
{ {
return size_cast<M>(std::make_index_sequence<M>{}); return size_cast<M>(std::make_index_sequence<M>{});
} }
/// Returns a zero vector.
static constexpr inline vector zero() noexcept
{
return {};
}
}; };
// Ensure vector is a POD type // Ensure vector is a POD type

Loading…
Cancel
Save