diff --git a/crest/Assets/Crest/Crest/Scripts/Helpers/MersenneTwisterRandom.cs b/crest/Assets/Crest/Crest/Scripts/Helpers/MersenneTwisterRandom.cs
new file mode 100644
index 000000000..e607d2f81
--- /dev/null
+++ b/crest/Assets/Crest/Crest/Scripts/Helpers/MersenneTwisterRandom.cs
@@ -0,0 +1,286 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WaveShapeCalculator
+{
+ using System;
+
+namespace Random
+{
+ /* C# Version Copyright (C) 2001 Akihilo Kramot (Takel). */
+ /* C# porting from a C-program for MT19937, originaly coded by */
+ /* Takuji Nishimura, considering the suggestions by */
+ /* Topher Cooper and Marc Rieffel in July-Aug. 1997. */
+ /* This library is free software under the Artistic license: */
+ /* */
+ /* You can find the original C-program at */
+ /* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html */
+ /* */
+
+ ///
+ /// Implements a Mersenne Twister Random Number Generator. This class provides the same interface
+ /// as the standard System.Random number generator, plus some additional functions.
+ ///
+
+ public class MersenneTwister: System.Random
+ {
+ /* Period parameters */
+ private const int N = 624;
+ private const int M = 397;
+ private const uint MATRIX_A = 0x9908b0df; /* constant vector a */
+ private const uint UPPER_MASK = 0x80000000; /* most significant w-r bits */
+ private const uint LOWER_MASK = 0x7fffffff; /* least significant r bits */
+
+ /* Tempering parameters */
+ private const uint TEMPERING_MASK_B = 0x9d2c5680;
+ private const uint TEMPERING_MASK_C = 0xefc60000;
+
+ private static uint TEMPERING_SHIFT_U( uint y ) { return ( y >> 11 ); }
+ private static uint TEMPERING_SHIFT_S( uint y ) { return ( y << 7 ); }
+ private static uint TEMPERING_SHIFT_T( uint y ) { return ( y << 15 ); }
+ private static uint TEMPERING_SHIFT_L( uint y ) { return ( y >> 18 ); }
+
+ private uint[] mt = new uint[N]; /* the array for the state vector */
+
+ private uint seed_;
+ private short mti;
+
+ private static uint[] mag01 = { 0x0, MATRIX_A };
+
+ ///
+ /// Create a twister with the specified seed. All sequences started with the same seed will contain
+ /// the same random numbers in the same order.
+ ///
+ /// The seed with which to start the twister.
+
+ public MersenneTwister( uint seed )
+ {
+ Seed = seed;
+ }
+
+
+ ///
+ /// Create a twister seeded from the system clock to make it as random as possible.
+ ///
+
+ public MersenneTwister()
+ : this( ( (uint) DateTime.Now.Ticks ) ) // A random initial seed is used.
+ {
+ }
+
+
+ ///
+ /// The seed that was used to start the random number generator.
+ /// Setting the seed resets the random number generator with the new seed.
+ /// All sequences started with the same seed will contain the same random numbers in the same order.
+ ///
+
+ public uint Seed
+ {
+ set
+ {
+ seed_ = value;
+
+ /* setting initial seeds to mt[N] using */
+ /* the generator Line 25 of Table 1 in */
+ /* [KNUTH 1981, The Art of Computer Programming */
+ /* Vol. 2 (2nd Ed.), pp102] */
+
+ mt[0] = seed_ & 0xffffffffU;
+ for ( mti = 1; mti < N; mti++ )
+ {
+ mt[mti] = ( 69069 * mt[mti - 1] ) & 0xffffffffU;
+ }
+ }
+
+ get
+ {
+ return seed_;
+ }
+ }
+
+
+ ///
+ /// Generate a random uint.
+ ///
+ /// A random uint.
+
+ protected uint GenerateUInt()
+ {
+ uint y;
+
+ /* mag01[x] = x * MATRIX_A for x=0,1 */
+
+ if ( mti >= N ) /* generate N words at one time */
+ {
+ short kk;
+
+ for ( kk = 0; kk < N - M; kk++ )
+ {
+ y = ( mt[kk] & UPPER_MASK ) | ( mt[kk + 1] & LOWER_MASK );
+ mt[kk] = mt[kk + M] ^ ( y >> 1 ) ^ mag01[y & 0x1];
+ }
+
+ for ( ; kk < N - 1; kk++ )
+ {
+ y = ( mt[kk] & UPPER_MASK ) | ( mt[kk + 1] & LOWER_MASK );
+ mt[kk] = mt[kk + ( M - N )] ^ ( y >> 1 ) ^ mag01[y & 0x1];
+ }
+
+ y = ( mt[N - 1] & UPPER_MASK ) | ( mt[0] & LOWER_MASK );
+ mt[N - 1] = mt[M - 1] ^ ( y >> 1 ) ^ mag01[y & 0x1];
+
+ mti = 0;
+ }
+
+ y = mt[mti++];
+ y ^= TEMPERING_SHIFT_U( y );
+ y ^= TEMPERING_SHIFT_S( y ) & TEMPERING_MASK_B;
+ y ^= TEMPERING_SHIFT_T( y ) & TEMPERING_MASK_C;
+ y ^= TEMPERING_SHIFT_L( y );
+
+ return y;
+ }
+
+
+ ///
+ /// Returns the next uint in the random sequence.
+ ///
+ /// The next uint in the random sequence.
+
+ public virtual uint NextUInt()
+ {
+ return this.GenerateUInt();
+ }
+
+
+ ///
+ /// Returns a random number between 0 and a specified maximum.
+ ///
+ /// The upper bound of the random number to be generated. maxValue must be greater than or equal to zero.
+ /// A 32-bit unsigned integer greater than or equal to zero, and less than maxValue; that is, the range of return values includes zero but not MaxValue.
+
+ public virtual uint NextUInt( uint maxValue )
+ {
+ return (uint) ( this.GenerateUInt() / ( (double) uint.MaxValue / maxValue ) );
+ }
+
+
+ ///
+ /// Returns an unsigned random number from a specified range.
+ ///
+ /// The lower bound of the random number returned.
+ /// The upper bound of the random number returned. maxValue must be greater than or equal to minValue.
+ /// A 32-bit signed integer greater than or equal to minValue and less than maxValue;
+ /// that is, the range of return values includes minValue but not MaxValue.
+ /// If minValue equals maxValue, minValue is returned.
+
+ public virtual uint NextUInt( uint minValue, uint maxValue ) /* throws ArgumentOutOfRangeException */
+ {
+ if (minValue >= maxValue)
+ {
+ if (minValue == maxValue)
+ {
+ return minValue;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException("minValue", "NextUInt() called with minValue >= maxValue");
+ }
+ }
+
+ return (uint) ( this.GenerateUInt() / ( (double) uint.MaxValue / ( maxValue - minValue ) ) + minValue );
+ }
+
+
+ ///
+ /// Returns a nonnegative random number.
+ ///
+ /// A 32-bit signed integer greater than or equal to zero and less than int.MaxValue.
+
+ public override int Next()
+ {
+ return (int) ( this.GenerateUInt() / 2 );
+ }
+
+
+ ///
+ /// Returns a nonnegative random number less than the specified maximum.
+ ///
+ /// The upper bound of the random number to be generated. maxValue must be greater than or equal to zero.
+ /// A 32-bit signed integer greater than or equal to zero, and less than maxValue;
+ /// that is, the range of return values includes zero but not MaxValue.
+
+ public override int Next( int maxValue ) /* throws ArgumentOutOfRangeException */
+ {
+ if ( maxValue <= 0 )
+ {
+ if ( maxValue == 0 )
+ return 0;
+ else
+ throw new ArgumentOutOfRangeException( "maxValue", "Next() called with a negative parameter" );
+ }
+
+ return (int) ( this.GenerateUInt() / ( uint.MaxValue / maxValue ) );
+ }
+
+
+ ///
+ /// Returns a signed random number from a specified range.
+ ///
+ /// The lower bound of the random number returned.
+ /// The upper bound of the random number returned. maxValue must be greater than or equal to minValue.
+ /// A 32-bit signed integer greater than or equal to minValue and less than maxValue;
+ /// that is, the range of return values includes minValue but not MaxValue.
+ /// If minValue equals maxValue, minValue is returned.
+
+ public override int Next( int minValue, int maxValue ) /* ArgumentOutOfRangeException */
+ {
+ if (minValue >= maxValue)
+ {
+ if (minValue == maxValue)
+ {
+ return minValue;
+ }
+ else
+ {
+ throw new ArgumentOutOfRangeException("minValue", "Next() called with minValue > maxValue");
+ }
+ }
+
+ return (int) ( this.GenerateUInt() / ( (double) uint.MaxValue / ( maxValue - minValue ) ) + minValue );
+ }
+
+
+ ///
+ /// Fills an array of bytes with random numbers from 0..255
+ ///
+ /// The array to be filled with random numbers.
+
+ public override void NextBytes( byte[] buffer ) /* throws ArgumentNullException*/
+ {
+ int bufLen = buffer.Length;
+
+ if ( buffer == null )
+ throw new ArgumentNullException("buffer");
+
+ for ( int idx = 0; idx < bufLen; idx++ )
+ buffer[idx] = (byte) ( this.GenerateUInt() / ( uint.MaxValue / byte.MaxValue ) );
+ }
+
+
+ ///
+ /// Returns a double-precision random number in the range [0..1[
+ ///
+ /// A random double-precision floating point number greater than or equal to 0.0, and less than 1.0.
+
+ public override double NextDouble()
+ {
+ return (double) this.GenerateUInt() / uint.MaxValue;
+ }
+ }
+}
+}
diff --git a/crest/Assets/Crest/Crest/Scripts/Shapes/OceanWaveSpectrum.cs b/crest/Assets/Crest/Crest/Scripts/Shapes/OceanWaveSpectrum.cs
index ba84a2567..d62e526ff 100644
--- a/crest/Assets/Crest/Crest/Scripts/Shapes/OceanWaveSpectrum.cs
+++ b/crest/Assets/Crest/Crest/Scripts/Shapes/OceanWaveSpectrum.cs
@@ -102,7 +102,8 @@ float ComputeWaveSpeed(float wavelength)
///
/// Samples spectrum to generate wave data. Wavelengths will be in ascending order.
///
- public void GenerateWaveData(int componentsPerOctave, ref float[] wavelengths, ref float[] anglesDeg)
+ public void GenerateWaveData(System.Random randomStateBkp, int componentsPerOctave, ref float[] wavelengths,
+ ref float[] anglesDeg)
{
var totalComponents = NUM_OCTAVES * componentsPerOctave;
@@ -122,9 +123,9 @@ public void GenerateWaveData(int componentsPerOctave, ref float[] wavelengths, r
// wavelengths in sorted order!
var minWavelengthi = minWavelength + invComponentsPerOctave * minWavelength * i;
var maxWavelengthi = Mathf.Min(minWavelengthi + invComponentsPerOctave * minWavelength, 2f * minWavelength);
- wavelengths[index] = Mathf.Lerp(minWavelengthi, maxWavelengthi, Random.value);
+ wavelengths[index] = Mathf.Lerp(minWavelengthi, maxWavelengthi, (float)randomStateBkp.NextDouble());
- var rnd = (i + Random.value) * invComponentsPerOctave;
+ var rnd = (i + (float)randomStateBkp.NextDouble()) * invComponentsPerOctave;
anglesDeg[index] = (2f * rnd - 1f) * _waveDirectionVariance;
}
diff --git a/crest/Assets/Crest/Crest/Scripts/Shapes/ShapeGerstnerBatched.cs b/crest/Assets/Crest/Crest/Scripts/Shapes/ShapeGerstnerBatched.cs
index 09cdc0efb..5e3f6b826 100644
--- a/crest/Assets/Crest/Crest/Scripts/Shapes/ShapeGerstnerBatched.cs
+++ b/crest/Assets/Crest/Crest/Scripts/Shapes/ShapeGerstnerBatched.cs
@@ -24,7 +24,7 @@ public class ShapeGerstnerBatched : MonoBehaviour, ICollProvider
[Range(0f, 1f)]
public float _weight = 1f;
- public int _randomSeed = 0;
+ public uint _randomSeed = 0;
// data for all components
float[] _wavelengths;
@@ -40,6 +40,7 @@ public class ShapeGerstnerBatched : MonoBehaviour, ICollProvider
// Shader to be used to render evaluate Gerstner waves for each LOD
Shader _waveShader;
+ private WaveShapeCalculator.Random.MersenneTwister randomGenerator;
static int sp_TwoPiOverWavelengths = Shader.PropertyToID("_TwoPiOverWavelengths");
static int sp_Amplitudes = Shader.PropertyToID("_Amplitudes");
@@ -84,12 +85,9 @@ void Start()
}
}
- void InitPhases()
+ void InitPhases(System.Random random)
{
// Set random seed to get repeatable results
- Random.State randomStateBkp = Random.state;
- Random.InitState(_randomSeed);
-
var totalComps = _componentsPerOctave * OceanWaveSpectrum.NUM_OCTAVES;
_phases = new float[totalComps];
for (var octave = 0; octave < OceanWaveSpectrum.NUM_OCTAVES; octave++)
@@ -97,12 +95,10 @@ void InitPhases()
for (var i = 0; i < _componentsPerOctave; i++)
{
var index = octave * _componentsPerOctave + i;
- var rnd = (i + Random.value) / _componentsPerOctave;
+ var rnd = (i + (float)random.NextDouble()) / _componentsPerOctave;
_phases[index] = 2f * Mathf.PI * rnd;
}
}
-
- Random.state = randomStateBkp;
}
public void SetOrigin(Vector3 newOrigin)
@@ -125,19 +121,18 @@ public void SetOrigin(Vector3 newOrigin)
void Update()
{
if (OceanRenderer.Instance == null) return;
-
+ //create or reseed
+ if (randomGenerator == null)
+ randomGenerator = new WaveShapeCalculator.Random.MersenneTwister(_randomSeed);
+ else
+ randomGenerator.Seed = _randomSeed;
if (_phases == null || _phases.Length != _componentsPerOctave * OceanWaveSpectrum.NUM_OCTAVES)
{
- InitPhases();
+ InitPhases(randomGenerator);
+ randomGenerator.Seed = _randomSeed; //reseed again after phases init
}
+ _spectrum.GenerateWaveData(randomGenerator,_componentsPerOctave, ref _wavelengths, ref _angleDegs);
- // Set random seed to get repeatable results
- Random.State randomStateBkp = Random.state;
- Random.InitState(_randomSeed);
-
- _spectrum.GenerateWaveData(_componentsPerOctave, ref _wavelengths, ref _angleDegs);
-
- Random.state = randomStateBkp;
UpdateAmplitudes();
@@ -272,7 +267,8 @@ int UpdateBatch(int lodIdx, int firstComponent, int lastComponentNonInc, IProper
if (dropped > 0)
{
- Debug.LogWarning(string.Format("Gerstner LOD{0}: Batch limit reached, dropped {1} wavelengths. To support bigger batch sizes, see the comment around the BATCH_SIZE declaration.", lodIdx, dropped), this);
+ //commented out to prevent too more warnings
+ //Debug.LogWarning($"Gerstner LOD{lodIdx}: Batch limit reached, dropped {dropped} wavelengths. To support bigger batch sizes, see the comment around the BATCH_SIZE declaration.", this);
numComponents = BATCH_SIZE;
}