Advertisement
ulfben

SquirrelNoise5

Aug 17th, 2021
1,259
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.71 KB | None | 0 0
  1. //-----------------------------------------------------------------------------------------------
  2. // SquirrelNoise5.hpp
  3. //  based on GDC 2017 talk "Math for Game Programmers: Noise-Based RNG": https://www.youtube.com/watch?v=LWFzPP8ZbdU
  4. #pragma once
  5.  
  6.  
  7. /////////////////////////////////////////////////////////////////////////////////////////////////
  8. // SquirrelNoise5 - Squirrel's Raw Noise utilities (version 5)
  9. //
  10. // This code is made available under the Creative Commons attribution 3.0 license (CC-BY-3.0 US):
  11. //  Attribution in source code comments (even closed-source/commercial code) is sufficient.
  12. //  License summary and text available at: https://creativecommons.org/licenses/by/3.0/us/
  13. //
  14. // These noise functions were written by Squirrel Eiserloh as a cheap and simple substitute for
  15. //  the [sometimes awful] bit-noise sample code functions commonly found on the web, many of which
  16. //  are hugely biased or terribly patterned, e.g. having bits which are on (or off) 75% or even
  17. //  100% of the time (or are excessively overkill/slow for our needs, such as MD5 or SHA).
  18. //
  19. // Note: This is work in progress; not all functions have been tested.  Use at your own risk.
  20. //  Please report any bugs, issues, or bothersome cases to SquirrelEiserloh at gmail.com.
  21. //
  22. // The following functions are all based on a simple bit-noise hash function which returns an
  23. //  unsigned integer containing 32 reasonably-well-scrambled bits, based on a given (signed)
  24. //  integer input parameter (position/index) and [optional] seed.  Kind of like looking up a
  25. //  value in an infinitely large [non-existent] table of previously rolled random numbers.
  26. //
  27. // These functions are deterministic and random-access / order-independent (i.e. state-free),
  28. //  so they are particularly well-suited for use in smoothed/fractal/simplex/Perlin noise
  29. //  functions and out-of-order (or or-demand) procedural content generation (i.e. that mountain
  30. //  village is the same whether you generated it first or last, ahead of time or just now).
  31. //
  32. // The N-dimensional variations simply hash their multidimensional coordinates down to a single
  33. //  32-bit index and then proceed as usual, so while results are not unique they should
  34. //  (hopefully) not seem locally predictable or repetitive.
  35. //
  36. /////////////////////////////////////////////////////////////////////////////////////////////////
  37.  
  38.  
  39. //-----------------------------------------------------------------------------------------------
  40. // Raw pseudorandom noise functions (random-access / deterministic).  Basis of all other noise.
  41. //
  42. constexpr unsigned int Get1dNoiseUint( int index, unsigned int seed=0 );
  43. constexpr unsigned int Get2dNoiseUint( int indexX, int indexY, unsigned int seed=0 );
  44. constexpr unsigned int Get3dNoiseUint( int indexX, int indexY, int indexZ, unsigned int seed=0 );
  45. constexpr unsigned int Get4dNoiseUint( int indexX, int indexY, int indexZ, int indexT, unsigned int seed=0 );
  46.  
  47. //-----------------------------------------------------------------------------------------------
  48. // Same functions, mapped to floats in [0,1] for convenience.
  49. //
  50. constexpr float Get1dNoiseZeroToOne( int index, unsigned int seed=0 );
  51. constexpr float Get2dNoiseZeroToOne( int indexX, int indexY, unsigned int seed=0 );
  52. constexpr float Get3dNoiseZeroToOne( int indexX, int indexY, int indexZ, unsigned int seed=0 );
  53. constexpr float Get4dNoiseZeroToOne( int indexX, int indexY, int indexZ, int indexT, unsigned int seed=0 );
  54.  
  55. //-----------------------------------------------------------------------------------------------
  56. // Same functions, mapped to floats in [-1,1] for convenience.
  57. //
  58. constexpr float Get1dNoiseNegOneToOne( int index, unsigned int seed=0 );
  59. constexpr float Get2dNoiseNegOneToOne( int indexX, int indexY, unsigned int seed=0 );
  60. constexpr float Get3dNoiseNegOneToOne( int indexX, int indexY, int indexZ, unsigned int seed=0 );
  61. constexpr float Get4dNoiseNegOneToOne( int indexX, int indexY, int indexZ, int indexT, unsigned int seed=0 );
  62.  
  63.  
  64. /////////////////////////////////////////////////////////////////////////////////////////////////
  65. // Inline function definitions below
  66. /////////////////////////////////////////////////////////////////////////////////////////////////
  67.  
  68. //-----------------------------------------------------------------------------------------------
  69. // Fast hash of an int32 into a different (unrecognizable) uint32.
  70. //
  71. // Returns an unsigned integer containing 32 reasonably-well-scrambled bits, based on the hash
  72. //  of a given (signed) integer input parameter (position/index) and [optional] seed.  Kind of
  73. //  like looking up a value in an infinitely large table of previously generated random numbers.
  74. //
  75. // I call this particular approach SquirrelNoise5 (5th iteration of my 1D raw noise function).
  76. //
  77. // Many thanks to Peter Schmidt-Nielsen whose outstanding analysis helped identify a weakness
  78. //  in the SquirrelNoise3 code I originally used in my GDC 2017 talk, "Noise-based RNG".
  79. //  Version 5 avoids a noise repetition found in version 3 at extremely high position values
  80. //  caused by a lack of influence by some of the high input bits onto some of the low output bits.
  81. //
  82. // The revised SquirrelNoise5 function ensures all input bits affect all output bits, and to
  83. //  (for me) a statistically acceptable degree.  I believe the worst-case here is in the amount
  84. //  of influence input position bit #30 has on output noise bit #0 (49.99%, vs. 50% ideal).
  85. //
  86. constexpr unsigned int SquirrelNoise5( int positionX, unsigned int seed )
  87. {
  88.     constexpr unsigned int SQ5_BIT_NOISE1 = 0xd2a80a3f; // 11010010101010000000101000111111
  89.     constexpr unsigned int SQ5_BIT_NOISE2 = 0xa884f197; // 10101000100001001111000110010111
  90.     constexpr unsigned int SQ5_BIT_NOISE3 = 0x6C736F4B; // 01101100011100110110111101001011
  91.     constexpr unsigned int SQ5_BIT_NOISE4 = 0xB79F3ABB; // 10110111100111110011101010111011
  92.     constexpr unsigned int SQ5_BIT_NOISE5 = 0x1b56c4f5; // 00011011010101101100010011110101
  93.  
  94.     unsigned int mangledBits = (unsigned int) positionX;
  95.     mangledBits *= SQ5_BIT_NOISE1;
  96.     mangledBits += seed;
  97.     mangledBits ^= (mangledBits >> 9);
  98.     mangledBits += SQ5_BIT_NOISE2;
  99.     mangledBits ^= (mangledBits >> 11);
  100.     mangledBits *= SQ5_BIT_NOISE3;
  101.     mangledBits ^= (mangledBits >> 13);
  102.     mangledBits += SQ5_BIT_NOISE4;
  103.     mangledBits ^= (mangledBits >> 15);
  104.     mangledBits *= SQ5_BIT_NOISE5;
  105.     mangledBits ^= (mangledBits >> 17);
  106.     return mangledBits;
  107. }
  108.  
  109.  
  110. //------------------------------------------------------------------------------------------------
  111. constexpr unsigned int Get1dNoiseUint( int positionX, unsigned int seed )
  112. {
  113.     return SquirrelNoise5( positionX, seed );
  114. }
  115.  
  116.  
  117. //-----------------------------------------------------------------------------------------------
  118. constexpr unsigned int Get2dNoiseUint( int indexX, int indexY, unsigned int seed )
  119. {
  120.     constexpr int PRIME_NUMBER = 198491317; // Large prime number with non-boring bits
  121.     return SquirrelNoise5( indexX + (PRIME_NUMBER * indexY), seed );
  122. }
  123.  
  124. //-----------------------------------------------------------------------------------------------
  125. constexpr unsigned int Get3dNoiseUint( int indexX, int indexY, int indexZ, unsigned int seed )
  126. {
  127.     constexpr int PRIME1 = 198491317; // Large prime number with non-boring bits
  128.     constexpr int PRIME2 = 6542989; // Large prime number with distinct and non-boring bits
  129.     return SquirrelNoise5( indexX + (PRIME1 * indexY) + (PRIME2 * indexZ), seed );
  130. }
  131.  
  132. //-----------------------------------------------------------------------------------------------
  133. constexpr unsigned int Get4dNoiseUint( int indexX, int indexY, int indexZ, int indexT, unsigned int seed )
  134. {
  135.     constexpr int PRIME1 = 198491317; // Large prime number with non-boring bits
  136.     constexpr int PRIME2 = 6542989; // Large prime number with distinct and non-boring bits
  137.     constexpr int PRIME3 = 357239; // Large prime number with distinct and non-boring bits
  138.     return SquirrelNoise5( indexX + (PRIME1 * indexY) + (PRIME2 * indexZ) + (PRIME3 * indexT), seed );
  139. }
  140.  
  141. //-----------------------------------------------------------------------------------------------
  142. constexpr float Get1dNoiseZeroToOne( int index, unsigned int seed )
  143. {
  144.     constexpr double ONE_OVER_MAX_UINT = (1.0 / (double) 0xFFFFFFFF);
  145.     return (float)( ONE_OVER_MAX_UINT * (double) SquirrelNoise5( index, seed ) );
  146. }
  147.  
  148. //-----------------------------------------------------------------------------------------------
  149. constexpr float Get2dNoiseZeroToOne( int indexX, int indexY, unsigned int seed )
  150. {
  151.     constexpr double ONE_OVER_MAX_UINT = (1.0 / (double) 0xFFFFFFFF);
  152.     return (float)( ONE_OVER_MAX_UINT * (double) Get2dNoiseUint( indexX, indexY, seed ) );
  153. }
  154.  
  155. //-----------------------------------------------------------------------------------------------
  156. constexpr float Get3dNoiseZeroToOne( int indexX, int indexY, int indexZ, unsigned int seed )
  157. {
  158.     constexpr double ONE_OVER_MAX_UINT = (1.0 / (double) 0xFFFFFFFF);
  159.     return (float)( ONE_OVER_MAX_UINT * (double) Get3dNoiseUint( indexX, indexY, indexZ, seed ) );
  160. }
  161.  
  162. //-----------------------------------------------------------------------------------------------
  163. constexpr float Get4dNoiseZeroToOne( int indexX, int indexY, int indexZ, int indexT, unsigned int seed )
  164. {
  165.     constexpr double ONE_OVER_MAX_UINT = (1.0 / (double) 0xFFFFFFFF);
  166.     return (float)( ONE_OVER_MAX_UINT * (double) Get4dNoiseUint( indexX, indexY, indexZ, indexT, seed ) );
  167. }
  168.  
  169.  
  170. //-----------------------------------------------------------------------------------------------
  171. constexpr float Get1dNoiseNegOneToOne( int index, unsigned int seed )
  172. {
  173.     constexpr double ONE_OVER_MAX_INT = (1.0 / (double) 0x7FFFFFFF);
  174.     return (float)( ONE_OVER_MAX_INT * (double) (int) SquirrelNoise5( index, seed ) );
  175. }
  176.  
  177.  
  178. //-----------------------------------------------------------------------------------------------
  179. constexpr float Get2dNoiseNegOneToOne( int indexX, int indexY, unsigned int seed )
  180. {
  181.     constexpr double ONE_OVER_MAX_INT = (1.0 / (double) 0x7FFFFFFF);
  182.     return (float)( ONE_OVER_MAX_INT * (double) (int) Get2dNoiseUint( indexX, indexY, seed ) );
  183. }
  184.  
  185.  
  186. //-----------------------------------------------------------------------------------------------
  187. constexpr float Get3dNoiseNegOneToOne( int indexX, int indexY, int indexZ, unsigned int seed )
  188. {
  189.     constexpr double ONE_OVER_MAX_INT = (1.0 / (double) 0x7FFFFFFF);
  190.     return (float)( ONE_OVER_MAX_INT * (double) (int) Get3dNoiseUint( indexX, indexY, indexZ, seed ) );
  191. }
  192.  
  193.  
  194. //-----------------------------------------------------------------------------------------------
  195. constexpr float Get4dNoiseNegOneToOne( int indexX, int indexY, int indexZ, int indexT, unsigned int seed )
  196. {
  197.     constexpr double ONE_OVER_MAX_INT = (1.0 / (double) 0x7FFFFFFF);
  198.     return (float)( ONE_OVER_MAX_INT * (double) (int) Get4dNoiseUint( indexX, indexY, indexZ, indexT, seed ) );
  199. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement