Added cImprovedNoise implementation.
This commit is contained in:
parent
ae15c2f78e
commit
f9cfc36643
@ -61,35 +61,6 @@ public:
|
||||
|
||||
|
||||
|
||||
/** Linearly interpolates between two values.
|
||||
Assumes that a_Ratio is in range [0, 1]. */
|
||||
inline static NOISE_DATATYPE Lerp(NOISE_DATATYPE a_Val1, NOISE_DATATYPE a_Val2, NOISE_DATATYPE a_Ratio)
|
||||
{
|
||||
return a_Val1 + (a_Val2 - a_Val1) * a_Ratio;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Linearly interpolates between two values, clamping the ratio to [0, 1] first. */
|
||||
inline static NOISE_DATATYPE ClampedLerp(NOISE_DATATYPE a_Val1, NOISE_DATATYPE a_Val2, NOISE_DATATYPE a_Ratio)
|
||||
{
|
||||
if (a_Ratio < 0)
|
||||
{
|
||||
return a_Val1;
|
||||
}
|
||||
if (a_Ratio > 1)
|
||||
{
|
||||
return a_Val2;
|
||||
}
|
||||
return Lerp(a_Val1, a_Val2, a_Ratio);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cNoise3DGenerator:
|
||||
|
||||
@ -249,10 +220,10 @@ void cNoise3DGenerator::GenerateNoiseArray(int a_ChunkX, int a_ChunkZ, NOISE_DAT
|
||||
NOISE_DATATYPE NoiseW[DIM_X * DIM_Y * DIM_Z]; // Workspace that the noise calculation can use and trash
|
||||
|
||||
// Our noise array has different layout, XZY, instead of regular chunk's XYZ, that's why the coords are "renamed"
|
||||
NOISE_DATATYPE StartX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width)) / m_FrequencyX;
|
||||
NOISE_DATATYPE EndX = ((NOISE_DATATYPE)((a_ChunkX + 1) * cChunkDef::Width) - 1) / m_FrequencyX;
|
||||
NOISE_DATATYPE StartZ = ((NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width)) / m_FrequencyZ;
|
||||
NOISE_DATATYPE EndZ = ((NOISE_DATATYPE)((a_ChunkZ + 1) * cChunkDef::Width) - 1) / m_FrequencyZ;
|
||||
NOISE_DATATYPE StartX = ((NOISE_DATATYPE)(a_ChunkX * cChunkDef::Width)) / m_FrequencyX;
|
||||
NOISE_DATATYPE EndX = ((NOISE_DATATYPE)((a_ChunkX + 1) * cChunkDef::Width)) / m_FrequencyX;
|
||||
NOISE_DATATYPE StartZ = ((NOISE_DATATYPE)(a_ChunkZ * cChunkDef::Width)) / m_FrequencyZ;
|
||||
NOISE_DATATYPE EndZ = ((NOISE_DATATYPE)((a_ChunkZ + 1) * cChunkDef::Width)) / m_FrequencyZ;
|
||||
NOISE_DATATYPE StartY = 0;
|
||||
NOISE_DATATYPE EndY = ((NOISE_DATATYPE)256) / m_FrequencyY;
|
||||
|
||||
|
@ -34,9 +34,9 @@ public:
|
||||
|
||||
protected:
|
||||
// Linear interpolation step sizes, must be divisors of cChunkDef::Width and cChunkDef::Height, respectively:
|
||||
static const int UPSCALE_X = 8;
|
||||
static const int UPSCALE_Y = 4;
|
||||
static const int UPSCALE_Z = 8;
|
||||
static const int UPSCALE_X = 4;
|
||||
static const int UPSCALE_Y = 8;
|
||||
static const int UPSCALE_Z = 4;
|
||||
|
||||
// Linear interpolation buffer dimensions, calculated from the step sizes:
|
||||
static const int DIM_X = 1 + cChunkDef::Width / UPSCALE_X;
|
||||
|
274
src/Noise.cpp
274
src/Noise.cpp
@ -2,6 +2,7 @@
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "Noise.h"
|
||||
#include "OSSupport\Timer.h"
|
||||
|
||||
#define FAST_FLOOR(x) (((x) < 0) ? (((int)x) - 1) : ((int)x))
|
||||
|
||||
@ -9,10 +10,110 @@
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
/** cImprovedPerlin noise test suite:
|
||||
- Generate a rather large 2D and 3D noise array and output it to a file
|
||||
- Compare performance of cCubicNoise and cImprovedNoise, both in single-value and 3D-array usages */
|
||||
static class cImprovedPerlinNoiseTest
|
||||
{
|
||||
public:
|
||||
cImprovedPerlinNoiseTest(void)
|
||||
{
|
||||
printf("Performing Improved Perlin Noise tests...\n");
|
||||
TestImage();
|
||||
TestSpeed();
|
||||
TestSpeedArr();
|
||||
printf("Improved Perlin Noise tests complete.\n");
|
||||
}
|
||||
|
||||
|
||||
/** Tests the noise by generating 2D and 3D images and dumping them to files. */
|
||||
void TestImage(void)
|
||||
{
|
||||
static const int SIZE_X = 256;
|
||||
static const int SIZE_Y = 256;
|
||||
static const int SIZE_Z = 16;
|
||||
|
||||
cImprovedNoise noise(1);
|
||||
std::unique_ptr<NOISE_DATATYPE[]> arr(new NOISE_DATATYPE[SIZE_X * SIZE_Y * SIZE_Z]);
|
||||
noise.Generate3D(arr.get(), SIZE_X, SIZE_Y, SIZE_Z, 0, 14, 0, 14, 0, 14);
|
||||
Debug3DNoise(arr.get(), SIZE_X, SIZE_Y, SIZE_Z, "ImprovedPerlinNoiseTest3D", 128);
|
||||
noise.Generate2D(arr.get(), SIZE_X, SIZE_Y, 0, 14, 15, 28);
|
||||
Debug2DNoise(arr.get(), SIZE_X, SIZE_Y, "ImprovedPerlinNoiseTest2D", 128);
|
||||
}
|
||||
|
||||
|
||||
/** Tests the speeds of cImprovedPerlin and cCubicNoise when generating individual values. */
|
||||
void TestSpeed(void)
|
||||
{
|
||||
cImprovedNoise improvedNoise(1);
|
||||
cNoise noise(1);
|
||||
cTimer timer;
|
||||
|
||||
// Measure the improvedNoise:
|
||||
NOISE_DATATYPE sum = 0;
|
||||
long long start = timer.GetNowTime();
|
||||
for (int i = 0; i < 100000000; i++)
|
||||
{
|
||||
sum += improvedNoise.GetValueAt(i, 0, -i);
|
||||
}
|
||||
long long finish = timer.GetNowTime();
|
||||
printf("cImprovedNoise took %.2f seconds; total is %f.\n", static_cast<float>(finish - start) / 1000.0f, sum);
|
||||
|
||||
// Measure the cubicNoise:
|
||||
sum = 0;
|
||||
start = timer.GetNowTime();
|
||||
for (int i = 0; i < 100000000; i++)
|
||||
{
|
||||
sum += noise.IntNoise3D(i, 0, -i);
|
||||
}
|
||||
finish = timer.GetNowTime();
|
||||
printf("cCubicNoise took %.2f seconds; total is %f.\n", static_cast<float>(finish - start) / 1000.0f, sum);
|
||||
}
|
||||
|
||||
|
||||
/** Tests the speeds of cImprovedPerlin and cCubicNoise when generating arrays. */
|
||||
void TestSpeedArr(void)
|
||||
{
|
||||
static const int SIZE_X = 256;
|
||||
static const int SIZE_Y = 256;
|
||||
static const int SIZE_Z = 16;
|
||||
|
||||
std::unique_ptr<NOISE_DATATYPE[]> arr(new NOISE_DATATYPE[SIZE_X * SIZE_Y * SIZE_Z]);
|
||||
cTimer timer;
|
||||
cImprovedNoise improvedNoise(1);
|
||||
cCubicNoise cubicNoise(1);
|
||||
|
||||
// Measure the improvedNoise:
|
||||
long long start = timer.GetNowTime();
|
||||
for (int i = 0; i < 40; i++)
|
||||
{
|
||||
improvedNoise.Generate3D(arr.get(), SIZE_X, SIZE_Y, SIZE_Z, 0, 14, 0, 14, 0, 14);
|
||||
}
|
||||
long long finish = timer.GetNowTime();
|
||||
printf("cImprovedNoise(arr) took %.2f seconds.\n", static_cast<float>(finish - start) / 1000.0f);
|
||||
|
||||
// Measure the cubicNoise:
|
||||
start = timer.GetNowTime();
|
||||
for (int i = 0; i < 40; i++)
|
||||
{
|
||||
cubicNoise.Generate3D(arr.get(), SIZE_X, SIZE_Y, SIZE_Z, 0, 14, 0, 14, 0, 14);
|
||||
}
|
||||
finish = timer.GetNowTime();
|
||||
printf("cCubicNoise(arr) took %.2f seconds.\n", static_cast<float>(finish - start) / 1000.0f);
|
||||
}
|
||||
} g_Test;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Globals:
|
||||
|
||||
void Debug3DNoise(const NOISE_DATATYPE * a_Noise, int a_SizeX, int a_SizeY, int a_SizeZ, const AString & a_FileNameBase)
|
||||
void Debug3DNoise(const NOISE_DATATYPE * a_Noise, int a_SizeX, int a_SizeY, int a_SizeZ, const AString & a_FileNameBase, NOISE_DATATYPE a_Coeff)
|
||||
{
|
||||
const int BUF_SIZE = 512;
|
||||
ASSERT(a_SizeX <= BUF_SIZE); // Just stretch it, if needed
|
||||
@ -29,7 +130,7 @@ void Debug3DNoise(const NOISE_DATATYPE * a_Noise, int a_SizeX, int a_SizeY, int
|
||||
unsigned char buf[BUF_SIZE];
|
||||
for (int x = 0; x < a_SizeX; x++)
|
||||
{
|
||||
buf[x] = (unsigned char)(std::min(255, std::max(0, (int)(128 + 32 * a_Noise[idx++]))));
|
||||
buf[x] = static_cast<unsigned char>(Clamp((int)(128 + a_Coeff * a_Noise[idx++]), 0, 255));
|
||||
}
|
||||
f1.Write(buf, a_SizeX);
|
||||
} // for y
|
||||
@ -50,7 +151,7 @@ void Debug3DNoise(const NOISE_DATATYPE * a_Noise, int a_SizeX, int a_SizeY, int
|
||||
unsigned char buf[BUF_SIZE];
|
||||
for (int x = 0; x < a_SizeX; x++)
|
||||
{
|
||||
buf[x] = (unsigned char)(std::min(255, std::max(0, (int)(128 + 32 * a_Noise[idx++]))));
|
||||
buf[x] = static_cast<unsigned char>(Clamp((int)(128 + a_Coeff * a_Noise[idx++]), 0, 255));
|
||||
}
|
||||
f2.Write(buf, a_SizeX);
|
||||
} // for z
|
||||
@ -65,7 +166,7 @@ void Debug3DNoise(const NOISE_DATATYPE * a_Noise, int a_SizeX, int a_SizeY, int
|
||||
|
||||
|
||||
|
||||
void Debug2DNoise(const NOISE_DATATYPE * a_Noise, int a_SizeX, int a_SizeY, const AString & a_FileNameBase)
|
||||
void Debug2DNoise(const NOISE_DATATYPE * a_Noise, int a_SizeX, int a_SizeY, const AString & a_FileNameBase, NOISE_DATATYPE a_Coeff)
|
||||
{
|
||||
const int BUF_SIZE = 512;
|
||||
ASSERT(a_SizeX <= BUF_SIZE); // Just stretch it, if needed
|
||||
@ -79,7 +180,7 @@ void Debug2DNoise(const NOISE_DATATYPE * a_Noise, int a_SizeX, int a_SizeY, cons
|
||||
unsigned char buf[BUF_SIZE];
|
||||
for (int x = 0; x < a_SizeX; x++)
|
||||
{
|
||||
buf[x] = (unsigned char)(std::min(255, std::max(0, (int)(128 + 32 * a_Noise[idx++]))));
|
||||
buf[x] = static_cast<unsigned char>(Clamp((int)(128 + a_Coeff * a_Noise[idx++]), 0, 255));
|
||||
}
|
||||
f1.Write(buf, a_SizeX);
|
||||
} // for y
|
||||
@ -791,6 +892,169 @@ void cCubicNoise::CalcFloorFrac(
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cImprovedNoise:
|
||||
|
||||
cImprovedNoise::cImprovedNoise(int a_Seed)
|
||||
{
|
||||
// Initialize the permutations with identity:
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
m_Perm[i] = i;
|
||||
}
|
||||
|
||||
// Randomize the permutation table - swap each element with a random other element:
|
||||
cNoise noise(a_Seed);
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
int rnd = (noise.IntNoise1DInt(i) / 7) % 256;
|
||||
std::swap(m_Perm[i], m_Perm[rnd]);
|
||||
}
|
||||
|
||||
// Copy the lower 256 entries into upper 256 entries:
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
m_Perm[i + 256] = m_Perm[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cImprovedNoise::Generate2D(
|
||||
NOISE_DATATYPE * a_Array,
|
||||
int a_SizeX, int a_SizeY,
|
||||
NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX,
|
||||
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY
|
||||
) const
|
||||
{
|
||||
size_t idx = 0;
|
||||
for (int y = 0; y < a_SizeY; y++)
|
||||
{
|
||||
NOISE_DATATYPE ratioY = static_cast<NOISE_DATATYPE>(y) / (a_SizeY - 1);
|
||||
NOISE_DATATYPE noiseY = Lerp(a_StartY, a_EndY, ratioY);
|
||||
int noiseYInt = FAST_FLOOR(noiseY);
|
||||
int yCoord = noiseYInt & 255;
|
||||
NOISE_DATATYPE noiseYFrac = noiseY - noiseYInt;
|
||||
NOISE_DATATYPE fadeY = Fade(noiseYFrac);
|
||||
for (int x = 0; x < a_SizeX; x++)
|
||||
{
|
||||
NOISE_DATATYPE ratioX = static_cast<NOISE_DATATYPE>(x) / (a_SizeX - 1);
|
||||
NOISE_DATATYPE noiseX = Lerp(a_StartX, a_EndX, ratioX);
|
||||
int noiseXInt = FAST_FLOOR(noiseX);
|
||||
int xCoord = noiseXInt & 255;
|
||||
NOISE_DATATYPE noiseXFrac = noiseX - noiseXInt;
|
||||
NOISE_DATATYPE fadeX = Fade(noiseXFrac);
|
||||
|
||||
// Hash the coordinates:
|
||||
int A = m_Perm[xCoord] + yCoord;
|
||||
int AA = m_Perm[A];
|
||||
int AB = m_Perm[A + 1];
|
||||
int B = m_Perm[xCoord + 1] + yCoord;
|
||||
int BA = m_Perm[B];
|
||||
int BB = m_Perm[B + 1];
|
||||
|
||||
// Lerp the gradients:
|
||||
a_Array[idx++] = Lerp(
|
||||
Lerp(Grad(m_Perm[AA], noiseXFrac, noiseYFrac, 0), Grad(m_Perm[BA], noiseXFrac - 1, noiseYFrac, 0), fadeX),
|
||||
Lerp(Grad(m_Perm[AB], noiseXFrac, noiseYFrac - 1, 0), Grad(m_Perm[BB], noiseXFrac - 1, noiseYFrac - 1, 0), fadeX),
|
||||
fadeY
|
||||
);
|
||||
} // for x
|
||||
} // for y
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cImprovedNoise::Generate3D(
|
||||
NOISE_DATATYPE * a_Array,
|
||||
int a_SizeX, int a_SizeY, int a_SizeZ,
|
||||
NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX,
|
||||
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY,
|
||||
NOISE_DATATYPE a_StartZ, NOISE_DATATYPE a_EndZ
|
||||
) const
|
||||
{
|
||||
size_t idx = 0;
|
||||
for (int z = 0; z < a_SizeZ; z++)
|
||||
{
|
||||
NOISE_DATATYPE ratioZ = static_cast<NOISE_DATATYPE>(z) / (a_SizeZ - 1);
|
||||
NOISE_DATATYPE noiseZ = Lerp(a_StartZ, a_EndZ, ratioZ);
|
||||
int noiseZInt = FAST_FLOOR(noiseZ);
|
||||
int zCoord = noiseZInt & 255;
|
||||
NOISE_DATATYPE noiseZFrac = noiseZ - noiseZInt;
|
||||
NOISE_DATATYPE fadeZ = Fade(noiseZFrac);
|
||||
for (int y = 0; y < a_SizeY; y++)
|
||||
{
|
||||
NOISE_DATATYPE ratioY = static_cast<NOISE_DATATYPE>(y) / (a_SizeY - 1);
|
||||
NOISE_DATATYPE noiseY = Lerp(a_StartY, a_EndY, ratioY);
|
||||
int noiseYInt = FAST_FLOOR(noiseY);
|
||||
int yCoord = noiseYInt & 255;
|
||||
NOISE_DATATYPE noiseYFrac = noiseY - noiseYInt;
|
||||
NOISE_DATATYPE fadeY = Fade(noiseYFrac);
|
||||
for (int x = 0; x < a_SizeX; x++)
|
||||
{
|
||||
NOISE_DATATYPE ratioX = static_cast<NOISE_DATATYPE>(x) / (a_SizeX - 1);
|
||||
NOISE_DATATYPE noiseX = Lerp(a_StartX, a_EndX, ratioX);
|
||||
int noiseXInt = FAST_FLOOR(noiseX);
|
||||
int xCoord = noiseXInt & 255;
|
||||
NOISE_DATATYPE noiseXFrac = noiseX - noiseXInt;
|
||||
NOISE_DATATYPE fadeX = Fade(noiseXFrac);
|
||||
|
||||
// Hash the coordinates:
|
||||
int A = m_Perm[xCoord] + yCoord;
|
||||
int AA = m_Perm[A] + zCoord;
|
||||
int AB = m_Perm[A + 1] + zCoord;
|
||||
int B = m_Perm[xCoord + 1] + yCoord;
|
||||
int BA = m_Perm[B] + zCoord;
|
||||
int BB = m_Perm[B + 1] + zCoord;
|
||||
|
||||
// Lerp the gradients:
|
||||
// TODO: This may be optimized by swapping the coords and recalculating most lerps only "once every x"
|
||||
a_Array[idx++] = Lerp(
|
||||
Lerp(
|
||||
Lerp(Grad(m_Perm[AA], noiseXFrac, noiseYFrac, noiseZFrac), Grad(m_Perm[BA], noiseXFrac - 1, noiseYFrac, noiseZFrac), fadeX),
|
||||
Lerp(Grad(m_Perm[AB], noiseXFrac, noiseYFrac - 1, noiseZFrac), Grad(m_Perm[BB], noiseXFrac - 1, noiseYFrac - 1, noiseZFrac), fadeX),
|
||||
fadeY
|
||||
),
|
||||
Lerp(
|
||||
Lerp(Grad(m_Perm[AA + 1], noiseXFrac, noiseYFrac, noiseZFrac - 1), Grad(m_Perm[BA + 1], noiseXFrac - 1, noiseYFrac, noiseZFrac - 1), fadeX),
|
||||
Lerp(Grad(m_Perm[AB + 1], noiseXFrac, noiseYFrac - 1, noiseZFrac - 1), Grad(m_Perm[BB + 1], noiseXFrac - 1, noiseYFrac - 1, noiseZFrac - 1), fadeX),
|
||||
fadeY
|
||||
),
|
||||
fadeZ
|
||||
);
|
||||
} // for x
|
||||
} // for y
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
NOISE_DATATYPE cImprovedNoise::GetValueAt(int a_X, int a_Y, int a_Z)
|
||||
{
|
||||
// Hash the coordinates:
|
||||
a_X = a_X & 255;
|
||||
a_Y = a_Y & 255;
|
||||
a_Z = a_Z & 255;
|
||||
int A = m_Perm[a_X] + a_Y;
|
||||
int AA = m_Perm[A] + a_Z;
|
||||
int AB = m_Perm[A + 1] + a_Z;
|
||||
int B = m_Perm[a_X + 1] + a_Y;
|
||||
int BA = m_Perm[B] + a_Z;
|
||||
int BB = m_Perm[B + 1] + a_Z;
|
||||
|
||||
return Grad(m_Perm[AA], 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cPerlinNoise:
|
||||
|
||||
|
105
src/Noise.h
105
src/Noise.h
@ -140,6 +140,63 @@ protected:
|
||||
|
||||
|
||||
|
||||
/** Improved noise, as described by Ken Perlin: http://mrl.nyu.edu/~perlin/paper445.pdf
|
||||
Implementation adapted from Perlin's Java implementation: http://mrl.nyu.edu/~perlin/noise/ */
|
||||
class cImprovedNoise
|
||||
{
|
||||
public:
|
||||
/** Constructs a new instance of the noise obbject.
|
||||
Note that this operation is quite expensive (the permutation array being constructed). */
|
||||
cImprovedNoise(int a_Seed);
|
||||
|
||||
|
||||
/** Fills a 2D array with the values of the noise. */
|
||||
void Generate2D(
|
||||
NOISE_DATATYPE * a_Array, ///< Array to generate into [x + a_SizeX * y]
|
||||
int a_SizeX, int a_SizeY, ///< Count of the array, in each direction
|
||||
NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array in the X direction
|
||||
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY ///< Noise-space coords of the array in the Y direction
|
||||
) const;
|
||||
|
||||
|
||||
/** Fills a 3D array with the values of the noise. */
|
||||
void Generate3D(
|
||||
NOISE_DATATYPE * a_Array, ///< Array to generate into [x + a_SizeX * y + a_SizeX * a_SizeY * z]
|
||||
int a_SizeX, int a_SizeY, int a_SizeZ, ///< Count of the array, in each direction
|
||||
NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array in the X direction
|
||||
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY, ///< Noise-space coords of the array in the Y direction
|
||||
NOISE_DATATYPE a_StartZ, NOISE_DATATYPE a_EndZ ///< Noise-space coords of the array in the Z direction
|
||||
) const;
|
||||
|
||||
/** Returns the value at the specified integral coords. Used for raw speed measurement. */
|
||||
NOISE_DATATYPE GetValueAt(int a_X, int a_Y, int a_Z);
|
||||
|
||||
protected:
|
||||
|
||||
/** The permutation table used by the noise function. Initialized using seed. */
|
||||
int m_Perm[512];
|
||||
|
||||
|
||||
/** Calculates the fade curve, 6 * t^5 - 15 * t^4 + 10 * t^3. */
|
||||
inline static NOISE_DATATYPE Fade(NOISE_DATATYPE a_T)
|
||||
{
|
||||
return a_T * a_T * a_T * (a_T * (a_T * 6 - 15) + 10);
|
||||
}
|
||||
|
||||
/** Returns the gradient value based on the hash. */
|
||||
inline static NOISE_DATATYPE Grad(int a_Hash, NOISE_DATATYPE a_X, NOISE_DATATYPE a_Y, NOISE_DATATYPE a_Z)
|
||||
{
|
||||
int hash = a_Hash % 16;
|
||||
NOISE_DATATYPE u = (hash < 8) ? a_X : a_Y;
|
||||
NOISE_DATATYPE v = (hash < 4) ? a_Y : (((hash == 12) || (hash == 14)) ? a_X : a_Z);
|
||||
return (((hash & 1) == 0) ? u : -u) + (((hash & 2) == 0) ? v : -v);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cPerlinNoise
|
||||
{
|
||||
public:
|
||||
@ -155,7 +212,7 @@ public:
|
||||
NOISE_DATATYPE * a_Array, ///< Array to generate into
|
||||
int a_SizeX, ///< Count of the array
|
||||
NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array
|
||||
NOISE_DATATYPE * a_Workspace = nullptr ///< Workspace that this function can use and trash
|
||||
NOISE_DATATYPE * a_Workspace = nullptr ///< Workspace that this function can use and trash
|
||||
) const;
|
||||
|
||||
|
||||
@ -164,7 +221,7 @@ public:
|
||||
int a_SizeX, int a_SizeY, ///< Count of the array, in each direction
|
||||
NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array in the X direction
|
||||
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY, ///< Noise-space coords of the array in the Y direction
|
||||
NOISE_DATATYPE * a_Workspace = nullptr ///< Workspace that this function can use and trash
|
||||
NOISE_DATATYPE * a_Workspace = nullptr ///< Workspace that this function can use and trash
|
||||
) const;
|
||||
|
||||
|
||||
@ -174,7 +231,7 @@ public:
|
||||
NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array in the X direction
|
||||
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY, ///< Noise-space coords of the array in the Y direction
|
||||
NOISE_DATATYPE a_StartZ, NOISE_DATATYPE a_EndZ, ///< Noise-space coords of the array in the Z direction
|
||||
NOISE_DATATYPE * a_Workspace = nullptr ///< Workspace that this function can use and trash
|
||||
NOISE_DATATYPE * a_Workspace = nullptr ///< Workspace that this function can use and trash
|
||||
) const;
|
||||
|
||||
protected:
|
||||
@ -376,8 +433,46 @@ NOISE_DATATYPE cNoise::LinearInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B,
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global functions:
|
||||
|
||||
extern void Debug2DNoise(const NOISE_DATATYPE * a_Noise, int a_SizeX, int a_SizeY, const AString & a_FileNameBase);
|
||||
extern void Debug3DNoise(const NOISE_DATATYPE * a_Noise, int a_SizeX, int a_SizeY, int a_SizeZ, const AString & a_FileNameBase);
|
||||
/** Exports the noise array into a file.
|
||||
a_Coeff specifies the value that each array value is multiplied by before being converted into a byte. */
|
||||
extern void Debug2DNoise(const NOISE_DATATYPE * a_Array, int a_SizeX, int a_SizeY, const AString & a_FileNameBase, NOISE_DATATYPE a_Coeff = 32);
|
||||
|
||||
/** Exports the noise array into a set of files, ordered by XY and XZ.
|
||||
a_Coeff specifies the value that each array value is multiplied by before being converted into a byte. */
|
||||
extern void Debug3DNoise(const NOISE_DATATYPE * a_Array, int a_SizeX, int a_SizeY, int a_SizeZ, const AString & a_FileNameBase, NOISE_DATATYPE a_Coeff = 32);
|
||||
|
||||
|
||||
|
||||
|
||||
/** Linearly interpolates between two values.
|
||||
Assumes that a_Ratio is in range [0, 1]. */
|
||||
inline NOISE_DATATYPE Lerp(NOISE_DATATYPE a_Val1, NOISE_DATATYPE a_Val2, NOISE_DATATYPE a_Ratio)
|
||||
{
|
||||
return a_Val1 + (a_Val2 - a_Val1) * a_Ratio;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Linearly interpolates between two values, clamping the ratio to [0, 1] first. */
|
||||
inline NOISE_DATATYPE ClampedLerp(NOISE_DATATYPE a_Val1, NOISE_DATATYPE a_Val2, NOISE_DATATYPE a_Ratio)
|
||||
{
|
||||
if (a_Ratio < 0)
|
||||
{
|
||||
return a_Val1;
|
||||
}
|
||||
if (a_Ratio > 1)
|
||||
{
|
||||
return a_Val2;
|
||||
}
|
||||
return Lerp(a_Val1, a_Val2, a_Ratio);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user