You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
8.8 KiB
C++
251 lines
8.8 KiB
C++
// Modified from original
|
|
|
|
/*
|
|
Based in part on Perlin noise
|
|
http ://mrl.nyu.edu/~perlin/doc/oscar.html#noise
|
|
Copyright(c) Ken Perlin
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"),
|
|
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
|
|
|
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
IN THE SOFTWARE.
|
|
*/
|
|
|
|
#ifndef CRYINCLUDE_CRYCOMMON_PNOISE3_H
|
|
#define CRYINCLUDE_CRYCOMMON_PNOISE3_H
|
|
#pragma once
|
|
|
|
#include <Random.h>
|
|
|
|
#define NOISE_TABLE_SIZE 256
|
|
#define NOISE_MASK (NOISE_TABLE_SIZE-1)
|
|
|
|
namespace
|
|
{
|
|
const int kDefaultSeed=0;
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
class CPNoise3
|
|
{
|
|
public:
|
|
CPNoise3(void)
|
|
{
|
|
SetSeedAndReinitialize(kDefaultSeed);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// 1D quality noise generator, good for many situations like up/down movements,
|
|
// flickering/ambient lights etc.
|
|
// A typical usage would be to pass system time multiplied by a frequency value, like:
|
|
// float fRes=pNoise->Noise1D(fCurrentTime*fFreq);
|
|
// the lower the frequency, the smoother the output
|
|
inline float Noise1D(float x)
|
|
{
|
|
// Compute what gradients to use
|
|
int qx0 = (int)floorf(x);
|
|
int qx1 = qx0 + 1;
|
|
float tx0 = x - (float)qx0;
|
|
float tx1 = tx0 - 1;
|
|
|
|
// Make sure we don't come outside the lookup table
|
|
qx0 = qx0 & NOISE_MASK;
|
|
qx1 = qx1 & NOISE_MASK;
|
|
|
|
// Compute the dotproduct between the vectors and the gradients
|
|
float v0 = m_gx[qx0]*tx0;
|
|
float v1 = m_gx[qx1]*tx1;
|
|
|
|
// Modulate with the weight function
|
|
float wx = (3 - 2*tx0)*tx0*tx0;
|
|
float v = v0 - wx*(v0 - v1);
|
|
|
|
return v;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// 2D quality noise generator, twice slower than Noise1D.
|
|
// A typical usage would be to pass 2d coordinates multiplied by a frequency value, like:
|
|
// float fRes=pNoise->Noise2D(fX*fFreq,fY*fFreq);
|
|
inline float Noise2D(float x, float y)
|
|
{
|
|
// Compute what gradients to use
|
|
int qx0 = (int)floorf(x);
|
|
int qx1 = qx0 + 1;
|
|
float tx0 = x - (float)qx0;
|
|
float tx1 = tx0 - 1;
|
|
|
|
int qy0 = (int)floorf(y);
|
|
int qy1 = qy0 + 1;
|
|
float ty0 = y - (float)qy0;
|
|
float ty1 = ty0 - 1;
|
|
|
|
// Make sure we don't come outside the lookup table
|
|
qx0 = qx0 & NOISE_MASK;
|
|
qx1 = qx1 & NOISE_MASK;
|
|
|
|
qy0 = qy0 & NOISE_MASK;
|
|
qy1 = qy1 & NOISE_MASK;
|
|
|
|
// Permutate values to get pseudo randomly chosen gradients
|
|
int q00 = m_p[(qy0 + m_p[qx0]) & NOISE_MASK];
|
|
int q01 = m_p[(qy0 + m_p[qx1]) & NOISE_MASK];
|
|
|
|
int q10 = m_p[(qy1 + m_p[qx0]) & NOISE_MASK];
|
|
int q11 = m_p[(qy1 + m_p[qx1]) & NOISE_MASK];
|
|
|
|
// Compute the dotproduct between the vectors and the gradients
|
|
float v00 = m_gx[q00]*tx0 + m_gy[q00]*ty0;
|
|
float v01 = m_gx[q01]*tx1 + m_gy[q01]*ty0;
|
|
|
|
float v10 = m_gx[q10]*tx0 + m_gy[q10]*ty1;
|
|
float v11 = m_gx[q11]*tx1 + m_gy[q11]*ty1;
|
|
|
|
// Modulate with the weight function
|
|
float wx = (3 - 2*tx0)*tx0*tx0;
|
|
float v0 = v00 - wx*(v00 - v01);
|
|
float v1 = v10 - wx*(v10 - v11);
|
|
|
|
float wy = (3 - 2*ty0)*ty0*ty0;
|
|
float v = v0 - wy*(v0 - v1);
|
|
|
|
return v;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// 3D quality noise generator, twice slower than Noise2D, so use with care...
|
|
// A typical usage would be to pass 3d coordinates multiplied by a frequency value, like:
|
|
// float fRes=pNoise->Noise2D(fX*fFreq,fY*fFreq,fZ*fFreq);
|
|
inline float Noise3D(float x, float y, float z)
|
|
{
|
|
// Compute what gradients to use
|
|
int qx0 = (int)floorf(x);
|
|
int qx1 = qx0 + 1;
|
|
float tx0 = x - (float)qx0;
|
|
float tx1 = tx0 - 1;
|
|
|
|
int qy0 = (int)floorf(y);
|
|
int qy1 = qy0 + 1;
|
|
float ty0 = y - (float)qy0;
|
|
float ty1 = ty0 - 1;
|
|
|
|
int qz0 = (int)floorf(z);
|
|
int qz1 = qz0 + 1;
|
|
float tz0 = z - (float)qz0;
|
|
float tz1 = tz0 - 1;
|
|
|
|
// Make sure we don't come outside the lookup table
|
|
qx0 = qx0 & NOISE_MASK;
|
|
qx1 = qx1 & NOISE_MASK;
|
|
|
|
qy0 = qy0 & NOISE_MASK;
|
|
qy1 = qy1 & NOISE_MASK;
|
|
|
|
qz0 = qz0 & NOISE_MASK;
|
|
qz1 = qz1 & NOISE_MASK;
|
|
|
|
// Permutate values to get pseudo randomly chosen gradients
|
|
int q000 = m_p[(qz0 + m_p[(qy0 + m_p[qx0]) & NOISE_MASK]) & NOISE_MASK];
|
|
int q001 = m_p[(qz0 + m_p[(qy0 + m_p[qx1]) & NOISE_MASK]) & NOISE_MASK];
|
|
|
|
int q010 = m_p[(qz0 + m_p[(qy1 + m_p[qx0]) & NOISE_MASK]) & NOISE_MASK];
|
|
int q011 = m_p[(qz0 + m_p[(qy1 + m_p[qx1]) & NOISE_MASK]) & NOISE_MASK];
|
|
|
|
int q100 = m_p[(qz1 + m_p[(qy0 + m_p[qx0]) & NOISE_MASK]) & NOISE_MASK];
|
|
int q101 = m_p[(qz1 + m_p[(qy0 + m_p[qx1]) & NOISE_MASK]) & NOISE_MASK];
|
|
|
|
int q110 = m_p[(qz1 + m_p[(qy1 + m_p[qx0]) & NOISE_MASK]) & NOISE_MASK];
|
|
int q111 = m_p[(qz1 + m_p[(qy1 + m_p[qx1]) & NOISE_MASK]) & NOISE_MASK];
|
|
|
|
// Compute the dotproduct between the vectors and the gradients
|
|
float v000 = m_gx[q000]*tx0 + m_gy[q000]*ty0 + m_gz[q000]*tz0;
|
|
float v001 = m_gx[q001]*tx1 + m_gy[q001]*ty0 + m_gz[q001]*tz0;
|
|
|
|
float v010 = m_gx[q010]*tx0 + m_gy[q010]*ty1 + m_gz[q010]*tz0;
|
|
float v011 = m_gx[q011]*tx1 + m_gy[q011]*ty1 + m_gz[q011]*tz0;
|
|
|
|
float v100 = m_gx[q100]*tx0 + m_gy[q100]*ty0 + m_gz[q100]*tz1;
|
|
float v101 = m_gx[q101]*tx1 + m_gy[q101]*ty0 + m_gz[q101]*tz1;
|
|
|
|
float v110 = m_gx[q110]*tx0 + m_gy[q110]*ty1 + m_gz[q110]*tz1;
|
|
float v111 = m_gx[q111]*tx1 + m_gy[q111]*ty1 + m_gz[q111]*tz1;
|
|
|
|
// Modulate with the weight function
|
|
float wx = (3 - 2*tx0)*tx0*tx0;
|
|
float v00 = v000 - wx*(v000 - v001);
|
|
float v01 = v010 - wx*(v010 - v011);
|
|
float v10 = v100 - wx*(v100 - v101);
|
|
float v11 = v110 - wx*(v110 - v111);
|
|
|
|
float wy = (3 - 2*ty0)*ty0*ty0;
|
|
float v0 = v00 - wy*(v00 - v01);
|
|
float v1 = v10 - wy*(v10 - v11);
|
|
|
|
float wz = (3 - 2*tz0)*tz0*tz0;
|
|
float v = v0 - wz*(v0 - v1);
|
|
|
|
return v;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// this needs to be called only once and it's already done by crysystem in the singleton constructor
|
|
// Note that every time the initialization function gets called, the PRNG will return
|
|
// different values, thus creating different gradients. Not a bad thing but probably
|
|
// not your expected behavior
|
|
|
|
inline void SetSeedAndReinitialize(uint seedValue)
|
|
{
|
|
int i, j, nSwap;
|
|
m_random_generator.Seed(seedValue);
|
|
|
|
// Initialize the permutation table
|
|
for(i = 0; i < NOISE_TABLE_SIZE; i++)
|
|
m_p[i] = i;
|
|
|
|
for(i = 0; i < NOISE_TABLE_SIZE; i++)
|
|
{
|
|
j = (m_random_generator.GenerateUint32())&NOISE_MASK;
|
|
|
|
nSwap = m_p[i];
|
|
m_p[i] = m_p[j];
|
|
m_p[j] = nSwap;
|
|
}
|
|
|
|
// Generate the gradient lookup tables
|
|
for(i = 0; i < NOISE_TABLE_SIZE; i++)
|
|
{
|
|
// Ken Perlin proposes that the gradients are taken from the unit
|
|
// circle/sphere for 2D/3D.
|
|
// So lets generate a good pseudo-random vector and normalize it
|
|
|
|
Vec3 v;
|
|
// cry_frand is in the 0..1 range
|
|
v.x=-0.5f+m_random_generator.GenerateFloat();
|
|
v.y=-0.5f+m_random_generator.GenerateFloat();
|
|
v.z=-0.5f+m_random_generator.GenerateFloat();
|
|
v.Normalize();
|
|
m_gx[i] = v.x;
|
|
m_gy[i] = v.y;
|
|
m_gz[i] = v.z;
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
CRndGen m_random_generator;
|
|
// Permutation table
|
|
unsigned char m_p[NOISE_TABLE_SIZE];
|
|
|
|
// Gradients
|
|
float m_gx[NOISE_TABLE_SIZE];
|
|
float m_gy[NOISE_TABLE_SIZE];
|
|
float m_gz[NOISE_TABLE_SIZE];
|
|
};
|
|
|
|
#endif // CRYINCLUDE_CRYCOMMON_PNOISE3_H
|