1
0

DistortedHeightmap: Optimized by linear interpolation

git-svn-id: http://mc-server.googlecode.com/svn/trunk@1451 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
madmaxoft@gmail.com 2013-05-06 16:46:48 +00:00
parent 1e71a8a6bf
commit 205ee49c79
2 changed files with 88 additions and 54 deletions

View File

@ -52,8 +52,6 @@ cDistortedHeightmap::cDistortedHeightmap(int a_Seed, cBiomeGen & a_BiomeGen) :
m_Noise3(a_Seed + 3000),
m_Noise4(a_Seed + 4000),
m_Noise5(a_Seed + 5000),
m_NoiseArrayX(m_NoiseArray),
m_NoiseArrayZ(m_NoiseArray + 17 * 17 * 32),
m_BiomeGen(a_BiomeGen),
m_UnderlyingHeiGen(a_Seed, a_BiomeGen),
m_HeightGen(&m_UnderlyingHeiGen, 64)
@ -86,47 +84,77 @@ void cDistortedHeightmap::PrepareState(int a_ChunkX, int a_ChunkZ)
m_CurChunkX = a_ChunkX;
m_CurChunkZ = a_ChunkZ;
m_HeightGen.GenHeightMap(a_ChunkX, a_ChunkZ, m_CurChunkHeights);
GenerateNoiseArray(m_NoiseArrayX, m_Noise1, m_Noise2, m_Noise3);
UpdateDistortAmps();
GenerateHeightArray();
}
void cDistortedHeightmap::GenerateNoiseArray(NOISE_DATATYPE * a_NoiseArray, cNoise & a_Noise1, cNoise & a_Noise2, cNoise & a_Noise3)
void cDistortedHeightmap::GenerateHeightArray(void)
{
// Parameters:
const int INTERPOL_X = 8;
const int INTERPOL_Y = 4;
const int INTERPOL_Z = 8;
ASSERT((NOISE_SIZE_Y % INTERPOL_Y) == 1); // Interpolation needs to set the 0-th and the last element
static const int INTERPOL_X = 8;
static const int INTERPOL_Y = 4;
static const int INTERPOL_Z = 8;
static const int DIM_X = 1 + (17 / INTERPOL_X);
static const int DIM_Y = 1 + (257 / INTERPOL_Y);
static const int DIM_Z = 1 + (17 / INTERPOL_Z);
NOISE_DATATYPE DistortNoiseX[DIM_X * DIM_Z * DIM_Y];
NOISE_DATATYPE DistortNoiseZ[DIM_X * DIM_Z * DIM_Y];
// TODO: This triple-loop should really be moved into the cPerlinNoise class for optimization
int idx = 0;
for (int y = 0; y < NOISE_SIZE_Y; y += INTERPOL_Y)
for (int y = 0; y < DIM_Y; y++)
{
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)y) / m_FrequencyY;
NOISE_DATATYPE * CurFloor = &(a_NoiseArray[y * 17 * 17]);
for (int z = 0; z < 17; z += INTERPOL_Z)
NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(y * INTERPOL_X)) / m_FrequencyY;
for (int z = 0; z < DIM_Z; z++)
{
NOISE_DATATYPE NoiseZ = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + z)) / m_FrequencyZ;
for (int x = 0; x < 17; x += INTERPOL_X)
NOISE_DATATYPE NoiseZ = ((NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + z * INTERPOL_Z)) / m_FrequencyZ;
for (int x = 0; x < DIM_X; x++)
{
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + x)) / m_FrequencyX;
CurFloor[x + 17 * z] =
a_Noise1.CubicNoise3D(NoiseX, NoiseY, NoiseZ) * (NOISE_DATATYPE)0.5 +
a_Noise2.CubicNoise3D(NoiseX / 2, NoiseY / 2, NoiseZ / 2) +
a_Noise3.CubicNoise3D(NoiseX / 4, NoiseY / 4, NoiseZ / 4) * 2;
}
}
// Linear-interpolate this XZ floor:
NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + x * INTERPOL_X)) / m_FrequencyX;
DistortNoiseX[idx] =
m_Noise1.CubicNoise3D(NoiseX, NoiseY, NoiseZ) * (NOISE_DATATYPE)0.5 +
m_Noise2.CubicNoise3D(NoiseX / 2, NoiseY / 2, NoiseZ / 2) +
m_Noise3.CubicNoise3D(NoiseX / 4, NoiseY / 4, NoiseZ / 4) * 2;
DistortNoiseZ[idx] =
m_Noise3.CubicNoise3D(NoiseX, NoiseY, NoiseZ) * (NOISE_DATATYPE)0.5 +
m_Noise2.CubicNoise3D(NoiseX / 2, NoiseY / 2, NoiseZ / 2) +
m_Noise1.CubicNoise3D(NoiseX / 4, NoiseY / 4, NoiseZ / 4) * 2;
idx += 1;
} // for x
} // for z
} // for y
// Convert from distortion into real height values:
for (int y = 0; y < DIM_Y; y++)
{
NOISE_DATATYPE * CurFloor = m_DistortedHeightmap + 17 * 17 * y * INTERPOL_Y;
for (int z = 0; z < DIM_Z; z++)
{
int idx = 17 * z * INTERPOL_Z;
int AmpIdx = 17 * z * INTERPOL_Z;
int NoiseArrayIdx = z * DIM_X + y * DIM_X * DIM_Z;
for (int x = 0; x < DIM_X; x++)
{
NOISE_DATATYPE DistX = DistortNoiseX[NoiseArrayIdx + x] * m_DistortAmpX[AmpIdx + x * INTERPOL_X];
NOISE_DATATYPE DistZ = DistortNoiseZ[NoiseArrayIdx + x] * m_DistortAmpZ[AmpIdx + x * INTERPOL_X];
DistX += (NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + x * INTERPOL_X);
DistZ += (NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + z * INTERPOL_Z);
// Adding 0.5 helps alleviate the interpolation artifacts
CurFloor[idx + x * INTERPOL_X] = (NOISE_DATATYPE)GetHeightmapAt(DistX, DistZ) + (NOISE_DATATYPE)0.5;
} // for x
} // for z
ArrayLinearInterpolate2D(CurFloor, 17, 17, INTERPOL_X, INTERPOL_Z);
} // for y
// Finish the 3D linear interpolation by interpolating between each XZ-floors on the Y axis
for (int y = 1; y < NOISE_SIZE_Y - 1; y++)
for (int y = 1; y < cChunkDef::Height; y++)
{
if ((y % INTERPOL_Y) == 0)
{
@ -135,9 +163,9 @@ void cDistortedHeightmap::GenerateNoiseArray(NOISE_DATATYPE * a_NoiseArray, cNoi
}
int LoFloorY = (y / INTERPOL_Y) * INTERPOL_Y;
int HiFloorY = LoFloorY + INTERPOL_Y;
NOISE_DATATYPE * LoFloor = &(a_NoiseArray[LoFloorY * 17 * 17]);
NOISE_DATATYPE * HiFloor = &(a_NoiseArray[HiFloorY * 17 * 17]);
NOISE_DATATYPE * CurFloor = &(a_NoiseArray[y * 17 * 17]);
NOISE_DATATYPE * LoFloor = &(m_DistortedHeightmap[LoFloorY * 17 * 17]);
NOISE_DATATYPE * HiFloor = &(m_DistortedHeightmap[HiFloorY * 17 * 17]);
NOISE_DATATYPE * CurFloor = &(m_DistortedHeightmap[y * 17 * 17]);
NOISE_DATATYPE Ratio = ((NOISE_DATATYPE)(y % INTERPOL_Y)) / INTERPOL_Y;
int idx = 0;
for (int z = 0; z < cChunkDef::Width; z++)
@ -146,10 +174,35 @@ void cDistortedHeightmap::GenerateNoiseArray(NOISE_DATATYPE * a_NoiseArray, cNoi
{
CurFloor[idx] = LoFloor[idx] + (HiFloor[idx] - LoFloor[idx]) * Ratio;
idx += 1;
} // for x
}
idx += 1; // Skipping one X column
} // for z
} // for y
/*
// DEBUG: Dump the distorted heightmap to a file for visual inspection
cFile f;
if (f.Open(Printf("DistortedHeightmap_%d_%d.grab", m_CurChunkX, m_CurChunkZ), cFile::fmWrite))
{
for (int z = 0; z < cChunkDef::Width; z++)
{
for (int y = cChunkDef::Height - 1; y >= 0; y--)
{
unsigned char Line[cChunkDef::Width];
int idx = z * 17 + y * 17 * 17;
for (int x = 0; x < cChunkDef::Width; x++)
{
Line[x] = (unsigned char)m_DistortedHeightmap[idx + x];
}
f.Write(Line, sizeof(Line));
} // for y
unsigned char Interrupt[2 * cChunkDef::Width];
memset(Interrupt, 0, cChunkDef::Width);
memset(Interrupt + cChunkDef::Width, 0xff, cChunkDef::Width);
f.Write(Interrupt, sizeof(Interrupt));
}
}
//*/
}
@ -167,7 +220,7 @@ void cDistortedHeightmap::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::He
cChunkDef::SetHeight(a_HeightMap, x, z, m_SeaLevel - 1);
for (int y = cChunkDef::Height - 1; y > m_SeaLevel - 1; y--)
{
int HeightMapHeight = GetValue(NoiseArrayIdx + 17 * 17 * y, x, z);
int HeightMapHeight = (int)m_DistortedHeightmap[NoiseArrayIdx + 17 * 17 * y];
if (y < HeightMapHeight)
{
cChunkDef::SetHeight(a_HeightMap, x, z, y);
@ -193,9 +246,9 @@ void cDistortedHeightmap::ComposeTerrain(cChunkDesc & a_ChunkDesc)
int NoiseArrayIdx = x + 17 * z;
int LastAir = a_ChunkDesc.GetHeight(x, z) + 1;
bool HasHadWater = false;
for (int y = LastAir; y > 0; y--)
for (int y = LastAir - 1; y > 0; y--)
{
int HeightMapHeight = GetValue(NoiseArrayIdx + 17 * 17 * y, x, z);
int HeightMapHeight = (int)m_DistortedHeightmap[NoiseArrayIdx + 17 * 17 * y];
if (y >= HeightMapHeight)
{
@ -263,20 +316,6 @@ int cDistortedHeightmap::GetHeightmapAt(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Z)
int cDistortedHeightmap::GetValue(int a_NoiseArrayIdx, int a_RelX, int a_RelZ)
{
int AmpIdx = a_RelX + 17 * a_RelZ;
NOISE_DATATYPE DistX = m_NoiseArrayX[a_NoiseArrayIdx] * m_DistortAmpX[AmpIdx];
NOISE_DATATYPE DistZ = m_NoiseArrayZ[a_NoiseArrayIdx] * m_DistortAmpZ[AmpIdx];
DistX += (NOISE_DATATYPE)(m_CurChunkX * cChunkDef::Width + a_RelX);
DistZ += (NOISE_DATATYPE)(m_CurChunkZ * cChunkDef::Width + a_RelZ);
return GetHeightmapAt(DistX, DistZ);
}
void cDistortedHeightmap::UpdateDistortAmps(void)
{
BiomeNeighbors Biomes;

View File

@ -48,11 +48,9 @@ protected:
int m_CurChunkX;
int m_CurChunkZ;
NOISE_DATATYPE m_NoiseArray[17 * 17 * NOISE_SIZE_Y];
NOISE_DATATYPE * m_NoiseArrayX;
NOISE_DATATYPE * m_NoiseArrayZ;
NOISE_DATATYPE m_DistortedHeightmap[17 * 17 * 257];
cBiomeGen & m_BiomeGen;
cBiomeGen & m_BiomeGen;
cHeiGenBiomal m_UnderlyingHeiGen; // This generator provides us with base heightmap (before distortion)
cHeiGenCache m_HeightGen; // Cache above m_UnderlyingHeiGen
@ -74,15 +72,12 @@ protected:
/// Unless the LastChunk coords are equal to coords given, prepares the internal state (noise arrays, heightmap)
void PrepareState(int a_ChunkX, int a_ChunkZ);
/// Generates the 3D noise array using the specified noise objects
void GenerateNoiseArray(NOISE_DATATYPE * a_NoiseArray, cNoise & a_Noise1, cNoise & a_Noise2, cNoise & a_Noise3);
/// Generates the m_DistortedHeightmap array for the current chunk
void GenerateHeightArray(void);
/// Calculates the heightmap value (before distortion) at the specified (floating-point) coords
int GetHeightmapAt(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Z);
/// Calculates the height (after distortion)
int GetValue(int a_NoiseArrayIdx, int a_RelX, int a_RelZ);
/// Updates m_DistortAmpX/Z[] based on m_CurChunkX and m_CurChunkZ
void UpdateDistortAmps(void);