Added better perlin terrain generation
Added function to scatter models onto the terrain
This commit is contained in:
@ -1,11 +1,8 @@
|
||||
#include "PerlinTerrainNode.h"
|
||||
|
||||
PerlinTerrainNode::PerlinTerrainNode(wstring name, wstring seed, float offsetX, float offsetY, float chunkSize, int layers, int widthX, int widthZ, float waterHeight, int cellSizeX, int cellSizeZ) : TerrainNode(name, seed, waterHeight, widthX, widthZ, cellSizeX, cellSizeZ)
|
||||
PerlinTerrainNode::PerlinTerrainNode(wstring name, wstring seed, float chunkSize, int widthX, int widthZ, float waterHeight, int cellSizeX, int cellSizeZ) : TerrainNode(name, seed, waterHeight, widthX, widthZ, cellSizeX, cellSizeZ)
|
||||
{
|
||||
_offsetX = offsetX;
|
||||
_offsetY = offsetY;
|
||||
_chunkSize = chunkSize;
|
||||
_layers = layers;
|
||||
|
||||
GeneratePerlinValues();
|
||||
if (!GeneratePerlinHeights())
|
||||
@ -14,44 +11,64 @@ PerlinTerrainNode::PerlinTerrainNode(wstring name, wstring seed, float offsetX,
|
||||
}
|
||||
}
|
||||
|
||||
void PerlinTerrainNode::GeneratePerlinValues()
|
||||
{
|
||||
std::seed_seq seedGenerator(_seedString.begin(), _seedString.end());
|
||||
std::mt19937 generator;
|
||||
generator.seed(seedGenerator);
|
||||
std::uniform_int_distribution<> dist(0, 511);
|
||||
char bufferChar;
|
||||
int newPosition;
|
||||
|
||||
_p.clear();
|
||||
copy(_staticP.begin(), _staticP.end(), back_inserter(_p));
|
||||
|
||||
for (int i = 0; i < 512; i++)
|
||||
{
|
||||
newPosition = dist(generator);
|
||||
bufferChar = _p[i];
|
||||
_p[i] = _p[newPosition];
|
||||
_p[newPosition] = bufferChar;
|
||||
}
|
||||
}
|
||||
|
||||
// Method for filling the height values array for the terrain generation
|
||||
bool PerlinTerrainNode::GeneratePerlinHeights()
|
||||
{
|
||||
for (int z = 0; z < _gridRows; z++)
|
||||
{
|
||||
float mapZ = ((float)z / (float)_gridRows) + 0.5f;
|
||||
float mapZ = ((float)z / (float)_gridRows);
|
||||
|
||||
for (int x = 0; x < _gridCols; x++)
|
||||
{
|
||||
float mapX = ((float)x / (float)_gridCols) + 0.5f;
|
||||
float mapX = ((float)x / (float)_gridCols);
|
||||
|
||||
float currentHeightValue = GetPerlinValueAt(_offsetX + mapX, _offsetY + mapZ, 8, 0.85f) - 0.25f;
|
||||
//float currentHeightValue = GetPerlinValueAt(mapX, mapZ, 8, 0.85f) - 0.25f;
|
||||
float currentHeightValue = 0.0f;
|
||||
|
||||
int octaves = 12;
|
||||
float currentOctaveValue = 1.0f;
|
||||
float stepOff = 1.0f;
|
||||
float stepTotal = 0.0f;
|
||||
// n covers the persistance, frequency and
|
||||
for (int n = 1; n <= octaves; n++)
|
||||
{
|
||||
currentHeightValue += stepOff * GetNoiseValueAt(((float)x * currentOctaveValue) / ((float)_gridCols / _chunkSize), ((float)z * currentOctaveValue) / ((float)_gridRows / _chunkSize));
|
||||
currentOctaveValue *= 2;
|
||||
stepTotal += stepOff;
|
||||
stepOff *= 0.5f;
|
||||
|
||||
}
|
||||
|
||||
//currentHeightValue = currentHeightValue / stepTotal; // *(currentHeightValue * 2.0f);
|
||||
//currentHeightValue = currentHeightValue - floor(currentHeightValue);
|
||||
_heightValues.push_back(currentHeightValue);
|
||||
_heightValues.push_back((currentHeightValue + 1.0f) * 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method for generating the permutation array needed for perlin noise
|
||||
void PerlinTerrainNode::GeneratePerlinValues()
|
||||
{
|
||||
// Set the permutation array length
|
||||
p.resize(256);
|
||||
|
||||
// Fill the permutation array with 0 to 255
|
||||
iota(p.begin(), p.end(), 0);
|
||||
|
||||
default_random_engine engine(_seedHash);
|
||||
|
||||
// Shuffle the array values using the seed value given
|
||||
shuffle(p.begin(), p.end(), engine);
|
||||
|
||||
// Duplicate the permutation results so our array is 512
|
||||
p.insert(p.end(), p.begin(), p.end());
|
||||
}
|
||||
|
||||
float PerlinTerrainNode::Fade(float t)
|
||||
{
|
||||
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||
@ -59,77 +76,56 @@ float PerlinTerrainNode::Fade(float t)
|
||||
|
||||
float PerlinTerrainNode::Grad(int hash, float x, float y)
|
||||
{
|
||||
// Fast Grad switch check converted from a java implimentation of perlin noise
|
||||
switch (hash & 0xF)
|
||||
int h = hash & 7;
|
||||
float u = y;
|
||||
float v = x;
|
||||
if (h < 4)
|
||||
{
|
||||
case 0x0: return x;
|
||||
case 0x1: return x + y;
|
||||
case 0x2: return y;
|
||||
case 0x3: return -x + y;
|
||||
case 0x4: return -x;
|
||||
case 0x5: return -x - y;
|
||||
case 0x6: return -y;
|
||||
case 0x7: return x - y;
|
||||
case 0x8: return x;
|
||||
case 0x9: return x + y;
|
||||
case 0xA: return y;
|
||||
case 0xB: return -x + y;
|
||||
case 0xC: return -x;
|
||||
case 0xD: return -x - y;
|
||||
case 0xE: return -y;
|
||||
case 0xF: return x - y;
|
||||
|
||||
default: return 0; // Never occurs
|
||||
u = x;
|
||||
v = y;
|
||||
}
|
||||
}
|
||||
|
||||
// Method to calculate the perlin value at x/y with the given octaves and persistance values, also normalised
|
||||
float PerlinTerrainNode::GetPerlinValueAt(float x, float y, int octaves, float persistance)
|
||||
{
|
||||
float total = 0.0f;
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
float maxValue = 0.0f;
|
||||
|
||||
for (int i = 0; i < octaves; i++)
|
||||
|
||||
float outA = u;
|
||||
if ((h & 1))
|
||||
{
|
||||
total += (GetNoiseValueAt(x * frequency, y * frequency) * amplitude);
|
||||
maxValue += amplitude;
|
||||
|
||||
amplitude *= persistance;
|
||||
frequency *= 2;
|
||||
outA = -u;
|
||||
}
|
||||
|
||||
return total / maxValue;
|
||||
float outB = 2.0f * v;
|
||||
if ((h & 2))
|
||||
{
|
||||
outB = -2.0f * v;
|
||||
}
|
||||
|
||||
return outA + outB;
|
||||
}
|
||||
|
||||
// Method to get the perlin noise value at x/y
|
||||
float PerlinTerrainNode::GetNoiseValueAt(float x, float y)
|
||||
{
|
||||
int x0 = (int)x & 255;
|
||||
int y0 = (int)y & 255;
|
||||
int ix0 = (int)floor(x);
|
||||
int iy0 = (int)floor(y);
|
||||
|
||||
int x1 = x0 + 1;
|
||||
int y1 = y0 + 1;
|
||||
float fx0 = x - (float)ix0;
|
||||
float fy0 = y - (float)iy0;
|
||||
float fx1 = fx0 - 1.0f;
|
||||
float fy1 = fy0 - 1.0f;
|
||||
|
||||
int ix1 = (ix0 + 1) & 0xff;
|
||||
int iy1 = (iy0 + 1) & 0xff;
|
||||
ix0 = ix0 & 0xff;
|
||||
iy0 = iy0 & 0xff;
|
||||
|
||||
float dx = x - (float)x0;
|
||||
float dy = y - (float)y0;
|
||||
float t = Fade(fy0);
|
||||
float s = Fade(fx0);
|
||||
|
||||
float u = Fade(dx);
|
||||
float v = Fade(dy);
|
||||
float nx0 = Grad(_p[ix0 + _p[iy0]], fx0, fy0);
|
||||
float nx1 = Grad(_p[ix0 + _p[iy1]], fx0, fy1);
|
||||
float n0 = SharedMethods::Lerp<float>(nx0, nx1, t);
|
||||
|
||||
int aa = p[p[x0] + y0];
|
||||
int ab = p[p[x0] + y1];
|
||||
int ba = p[p[x1] + y0];
|
||||
int bb = p[p[x1] + y1];
|
||||
nx0 = Grad(_p[ix1 + _p[iy0]], fx1, fy0);
|
||||
nx1 = Grad(_p[ix1 + _p[iy1]], fx1, fy1);
|
||||
float n1 = SharedMethods::Lerp<float>(nx0, nx1, t);
|
||||
|
||||
float na0 = Grad(aa, dx, dy);
|
||||
float na1 = Grad(ba, dx - 1.0f, dy);
|
||||
float nal = SharedMethods::Lerp(na0, na1, u);
|
||||
|
||||
float nb0 = Grad(ab, dx, dy - 1.0f);
|
||||
float nb1 = Grad(bb, dx - 1.0f, dy - 1.0f);
|
||||
float nbl = SharedMethods::Lerp(nb0, nb1, u);
|
||||
|
||||
return (SharedMethods::Lerp(nal, nbl, v) + 1.0f) / 2.0f;
|
||||
return 0.507f * SharedMethods::Lerp(n0, n1, s);
|
||||
}
|
Reference in New Issue
Block a user