From 94d9142ebfb389015da75690c87d299a51fc76b5 Mon Sep 17 00:00:00 2001 From: "C. J. Howard" Date: Wed, 19 Oct 2022 17:26:50 +0800 Subject: [PATCH] Simplify noise function signatures and provide default parameter values --- src/game/load.cpp | 39 +++++++++----------- src/math/hash/hash.hpp | 1 + src/math/hash/make-uint.hpp | 68 ++++++++++++++++++++++++++++++++++ src/math/hash/pcg.hpp | 48 ++++++------------------ src/math/noise/fbm.hpp | 10 +++-- src/math/noise/simplex.hpp | 22 +++++++---- src/math/noise/voronoi.hpp | 73 ++++++++++++++++++------------------- src/math/vector.hpp | 6 +++ 8 files changed, 159 insertions(+), 108 deletions(-) create mode 100644 src/math/hash/make-uint.hpp diff --git a/src/game/load.cpp b/src/game/load.cpp index fca8694..de801b1 100644 --- a/src/game/load.cpp +++ b/src/game/load.cpp @@ -48,6 +48,7 @@ void biome(game::context& ctx, const std::filesystem::path& path) { ctx.logger->push_task("Loading biome from \"" + path.string() + "\""); + /* image img; img.format(1, 1); img.resize(1024, 1024); @@ -113,7 +114,7 @@ void biome(game::context& ctx, const std::filesystem::path& path) // f2_displacement, // f2_id edge_sqr_distance - ] = math::noise::voronoi::f1_edge({position[0]}, 1.0f, {0.0f}, &math::hash::pcg); + ] = math::noise::voronoi::f1_edge(position); float f1_distance = std::sqrt(f1_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_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 { @@ -194,38 +195,32 @@ void biome(game::context& ctx, const std::filesystem::path& path) ( [](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; std::size_t octaves = 4; float lacunarity = 3.0f; float gain = 0.5f; - auto noise = static_cast&, decltype(hash))>(math::noise::simplex); - auto hash = static_cast(*)(const math::vector&)>(math::hash::pcg); float2 position = float2{x, z} * frequency; - /* - float n = math::noise::fbm + float fbm = math::noise::fbm ( position, octaves, lacunarity, - gain, - noise, - hash + gain ); - */ - //float n = math::noise::voronoi::f1(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; } ); diff --git a/src/math/hash/hash.hpp b/src/math/hash/hash.hpp index 5bb7214..813364d 100644 --- a/src/math/hash/hash.hpp +++ b/src/math/hash/hash.hpp @@ -27,6 +27,7 @@ namespace hash {} } // namespace math +#include "math/hash/make-uint.hpp" #include "math/hash/pcg.hpp" #endif // ANTKEEPER_MATH_HASH_HPP diff --git a/src/math/hash/make-uint.hpp b/src/math/hash/make-uint.hpp new file mode 100644 index 0000000..46a7fa0 --- /dev/null +++ b/src/math/hash/make-uint.hpp @@ -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 . + */ + +#ifndef ANTKEEPER_MATH_HASH_MAKE_UINT_HPP +#define ANTKEEPER_MATH_HASH_MAKE_UINT_HPP + +#include +#include + +namespace math { +namespace hash { + +/** + * Provides an unsigned integer type of equivalent size to type @p T. + */ +template +struct make_uint +{ + static_assert(std::is_integral::value); + + /// Unsigned integer type of equivalent size to type @p T. + typedef typename std::make_unsigned::type type; +}; + +/// Provides an unsigned integer type of equivalent size to `float`. +template<> +struct make_uint +{ + 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 +{ + 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 +using make_uint_t = typename make_uint::type; + +} // namespace hash +} // namespace math + +#endif // ANTKEEPER_MATH_HASH_MAKE_UINT_HPP diff --git a/src/math/hash/pcg.hpp b/src/math/hash/pcg.hpp index 011935a..d9a307b 100644 --- a/src/math/hash/pcg.hpp +++ b/src/math/hash/pcg.hpp @@ -21,42 +21,13 @@ #define ANTKEEPER_MATH_HASH_PCG_HPP #include "math/vector.hpp" +#include "math/hash/make-uint.hpp" #include #include namespace math { namespace hash { -/** - * Provides an unsigned integer type of equivalent size to type @p T. - */ -template -struct pcg_make_uint -{ - static_assert(std::is_integral::value); - - /// Unsigned integer type of equivalent size to type @p T. - typedef typename std::make_unsigned::type type; -}; - -/// Provides an unsigned integer type of equivalent to `float`. -template<> -struct pcg_make_uint -{ - typedef std::uint32_t type; -}; - -/// Provides an unsigned integer type of equivalent to `double`. -template<> -struct pcg_make_uint -{ - typedef std::uint64_t type; -}; - -/// Helper type for pcg_make_uint. -template -using pcg_make_uint_t = typename pcg_make_uint::type; - /// @private template constexpr T pcg_multiplier = 0; @@ -197,7 +168,10 @@ constexpr vector pcg_uvec4(vector x) noexcept * * @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 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 -inline constexpr vector, N> pcg(const vector& x) noexcept +inline constexpr vector, N> pcg(const vector& 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) - return pcg_uvec1>(vector, N>(x)); + return pcg_uvec1>(vector, N>(x)); else if constexpr (N == 2) - return pcg_uvec2>(vector, N>(x)); + return pcg_uvec2>(vector, N>(x)); else if constexpr (N == 3) - return pcg_uvec3>(vector, N>(x)); + return pcg_uvec3>(vector, N>(x)); else - return pcg_uvec4>(vector, N>(x)); + return pcg_uvec4>(vector, N>(x)); } /// @} diff --git a/src/math/noise/fbm.hpp b/src/math/noise/fbm.hpp index 29268c5..26ffe89 100644 --- a/src/math/noise/fbm.hpp +++ b/src/math/noise/fbm.hpp @@ -20,6 +20,9 @@ #ifndef 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 @@ -31,7 +34,6 @@ namespace noise { * * @tparam T Real type. * @tparam N Number of dimensions. - * @tparam U Hash function return type. * * @param x n-dimensional input value. * @param octaves Number of octaves. @@ -41,15 +43,15 @@ namespace noise { * @param hash Hash function. * */ -template +template T fbm ( vector x, std::size_t octaves, T lacunarity, T gain, - T (*noise)(const vector&, vector (*)(const vector&)), - vector (*hash)(const vector&) + T (*noise)(const vector&, vector, N> (*)(const vector&)) = &simplex, + vector, N> (*hash)(const vector&) = &hash::pcg ) { T amplitude{1}; diff --git a/src/math/noise/simplex.hpp b/src/math/noise/simplex.hpp index fb617ca..63a5541 100644 --- a/src/math/noise/simplex.hpp +++ b/src/math/noise/simplex.hpp @@ -21,6 +21,8 @@ #define ANTKEEPER_MATH_NOISE_SIMPLEX_HPP #include "math/vector.hpp" +#include "math/hash/make-uint.hpp" +#include "math/hash/pcg.hpp" #include #include @@ -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://math.stackexchange.com/questions/474638/radius-and-amplitude-of-kernel-for-simplex-noise/1901116 */ -template -T simplex(const vector& x, vector (*hash)(const vector&)) +template +T simplex +( + const vector& x, + vector, N> (*hash)(const vector&) = &hash::pcg +) { // Skewing (F) and unskewing (G) factors static const T f = (std::sqrt(static_cast(N + 1)) - T{1}) / static_cast(N); @@ -137,13 +143,13 @@ T simplex(const vector& x, vector (*hash)(const vector&)) static const T corner_normalization = T{1} / ((static_cast(N) / std::sqrt(static_cast(N + 1))) * falloff(static_cast(N) / (T{4} * static_cast(N + 1)))); // 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(N)) / math::length(simplex_edges[0])); + static const T edge_normalization = corner_normalization * (std::sqrt(static_cast(N)) / length(simplex_edges[0])); // Skew input position to get the origin vertex of the unit hypercube cell to which they belong - const vector origin_vertex = math::floor(x + math::sum(x) * f); + const vector origin_vertex = floor(x + sum(x) * f); // Displacement vector from origin vertex position to input position - const vector dx = x - origin_vertex + math::sum(origin_vertex) * g; + const vector dx = x - origin_vertex + sum(origin_vertex) * g; // Find axis traversal order vector axis_order; @@ -170,13 +176,13 @@ T simplex(const vector& x, vector (*hash)(const vector&)) const vector d = dx - (current_vertex - origin_vertex) + g * static_cast(i); // Calculate falloff - T t = falloff(math::length_squared(d)); + T t = falloff(length_squared(d)); if (t > T{0}) { - const auto gradient_index = hash(current_vertex)[0] % simplex_edges.size(); + const hash::make_uint_t gradient_index = hash(current_vertex)[0] % simplex_edges.size(); const vector& gradient = simplex_edges[gradient_index]; - n += math::dot(d, gradient) * t; + n += dot(d, gradient) * t; } } diff --git a/src/math/noise/voronoi.hpp b/src/math/noise/voronoi.hpp index 065d86d..0d64edc 100644 --- a/src/math/noise/voronoi.hpp +++ b/src/math/noise/voronoi.hpp @@ -21,6 +21,8 @@ #define ANTKEEPER_MATH_NOISE_VORONOI_HPP #include "math/vector.hpp" +#include "math/hash/make-uint.hpp" +#include "math/hash/pcg.hpp" #include #include #include @@ -96,7 +98,6 @@ constexpr auto kernel = generate_kernel(std::make_index_sequence(std::make_index_sequence +template std::tuple < // F1 square distance to center @@ -115,27 +116,27 @@ std::tuple vector, // F1 hash - U + hash::make_uint_t > f1 ( const vector& position, - T randomness, - const vector& tiling, - vector (*hash)(const vector&) + T randomness = T{1}, + const vector& tiling = vector::zero(), + vector, N> (*hash)(const vector&) = &hash::pcg ) { // Calculate factor which scales hash value onto `[0, 1]`, modulated by desired randomness - T hash_scale = (T{1} / static_cast(std::numeric_limits::max())) * randomness; + T hash_scale = (T{1} / static_cast(std::numeric_limits>::max())) * randomness; // Get integer and fractional parts - vector position_i = math::floor(position - T{1.5}); + vector position_i = floor(position - T{1.5}); vector position_f = position - position_i; // Find the F1 cell T f1_sqr_distance = std::numeric_limits::infinity(); vector f1_displacement; - U f1_hash; + hash::make_uint_t f1_hash; for (std::size_t i = 0; i < kernel_size; ++i) { // Get kernel offset for current cell @@ -150,7 +151,7 @@ f1 } // Calculate hash values for the hash position - vector hash_i = hash(hash_position); + vector, N> hash_i = hash(hash_position); // Convert hash values to pseudorandom fractional offset vector offset_f = vector(hash_i) * hash_scale; @@ -159,7 +160,7 @@ f1 vector displacement = (offset_i + offset_f) - position_f; // Calculate square distance to the current cell center - T sqr_distance = math::length_squared(displacement); + T sqr_distance = length_squared(displacement); // Update F1 cell if (sqr_distance < f1_sqr_distance) @@ -183,7 +184,6 @@ f1 * * @tparam T Real type. * @tparam N Number of dimensions. - * @tparam U Hash function return type. * * @param position Input position. * @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. */ -template +template std::tuple < // F1 square distance to center @@ -202,7 +202,7 @@ std::tuple vector, // F1 hash - U, + hash::make_uint_t, // Edge square distance T @@ -210,23 +210,23 @@ std::tuple f1_edge ( const vector& position, - T randomness, - const vector& tiling, - vector (*hash)(const vector&) + T randomness = T{1}, + const vector& tiling = vector::zero(), + vector, N> (*hash)(const vector&) = &hash::pcg ) { // Calculate factor which scales hash value onto `[0, 1]`, modulated by desired randomness - T hash_scale = (T{1} / static_cast(std::numeric_limits::max())) * randomness; + T hash_scale = (T{1} / static_cast(std::numeric_limits>::max())) * randomness; // Get integer and fractional parts - vector position_i = math::floor(position - T{1.5}); + vector position_i = floor(position - T{1.5}); vector position_f = position - position_i; // Find F1 cell T f1_sqr_distance_center = std::numeric_limits::infinity(); vector displacement_cache[kernel_size]; std::size_t f1_i = 0; - U f1_hash; + hash::make_uint_t f1_hash; for (std::size_t i = 0; i < kernel_size; ++i) { // Get kernel offset for current cell @@ -241,7 +241,7 @@ f1_edge } // Calculate hash values for the hash position - vector hash_i = hash(hash_position); + vector, N> hash_i = hash(hash_position); // Convert hash values to pseudorandom fractional offset vector offset_f = vector(hash_i) * hash_scale; @@ -250,7 +250,7 @@ f1_edge displacement_cache[i] = (offset_i + offset_f) - position_f; // 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 if (sqr_distance < f1_sqr_distance_center) @@ -279,10 +279,10 @@ f1_edge const vector midpoint = (f1_displacement + displacement) * T{0.5}; // Calculate direction from the F1 cell to current cell - const vector direction = math::normalize(displacement - f1_displacement); + const vector direction = normalize(displacement - f1_displacement); // 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 if (sqr_distance < edge_sqr_distance_edge) @@ -303,7 +303,6 @@ f1_edge * * @tparam T Real type. * @tparam N Number of dimensions. - * @tparam U Hash function return type. * * @param position Input position. * @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. */ -template +template std::tuple < // F1 square distance to center @@ -322,7 +321,7 @@ std::tuple vector, // F1 hash - U, + hash::make_uint_t, // F2 square distance to center T, @@ -331,30 +330,30 @@ std::tuple vector, // F2 hash - U + hash::make_uint_t > f1_f2 ( const vector& position, - T randomness, - const vector& tiling, - vector (*hash)(const vector&) + T randomness = T{1}, + const vector& tiling = vector::zero(), + vector, N> (*hash)(const vector&) = &hash::pcg ) { // Calculate factor which scales hash value onto `[0, 1]`, modulated by desired randomness - T hash_scale = (T{1} / static_cast(std::numeric_limits::max())) * randomness; + T hash_scale = (T{1} / static_cast(std::numeric_limits>::max())) * randomness; // Get integer and fractional parts - vector position_i = math::floor(position - T{1.5}); + vector position_i = floor(position - T{1.5}); vector position_f = position - position_i; // Find the F1 and F2 cells T f1_sqr_distance_center = std::numeric_limits::infinity(); vector f1_displacement = {0, 0}; - U f1_hash = 0; + hash::make_uint_t f1_hash = 0; T f2_sqr_distance_center = std::numeric_limits::infinity(); vector f2_displacement = {0, 0}; - U f2_hash = 0; + hash::make_uint_t f2_hash = 0; for (std::size_t i = 0; i < kernel_size; ++i) { // Get kernel offset for current cell @@ -369,7 +368,7 @@ f1_f2 } // Calculate hash values for the hash position - vector hash_i = hash(hash_position); + vector, N> hash_i = hash(hash_position); // Convert hash values to pseudorandom fractional offset vector offset_f = vector(hash_i) * hash_scale; @@ -378,7 +377,7 @@ f1_f2 vector displacement = (offset_i + offset_f) - position_f; // 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 if (sqr_distance < f1_sqr_distance_center) diff --git a/src/math/vector.hpp b/src/math/vector.hpp index 8a58e4b..371658c 100644 --- a/src/math/vector.hpp +++ b/src/math/vector.hpp @@ -254,6 +254,12 @@ struct vector { return size_cast(std::make_index_sequence{}); } + + /// Returns a zero vector. + static constexpr inline vector zero() noexcept + { + return {}; + } }; // Ensure vector is a POD type