Generator - Implementing parameters for various ore generations, refactoring and documenting functions.

This commit is contained in:
2024-12-22 06:57:29 -06:00
parent 88d7ead713
commit 8e8ad07d59
2 changed files with 189 additions and 60 deletions

View File

@@ -14,34 +14,122 @@ namespace CaveGame::Core
class Generator
{
public:
static constexpr int PrecomputedWhiteNoiseResolution = 2048;
/// Defines the sample count for the pre-generated RNG lookup table.
static constexpr int PrecomputedWhiteNoiseResolution = 2048;
/// Shifts the ground-level of terrain vertically by this many tiles.
#pragma region Surface Parameters
static constexpr float BaseSurfaceLvl = 100.f;
static constexpr float HeightMapHighPassAmplitude = 700.f;
static constexpr float HeightMapHighPassScale = 700.f;
static constexpr float HeightMapLowPassAmplitude = 85.f;
static constexpr float HeightMapLowPassScale = 64.f;
static constexpr float TopSoilDepth = 345.f;
#pragma endregion
#pragma region Cave Parameters
static constexpr float CaveInputScale = 800.f;
static constexpr float CaveOutputScale = 1.20f;
static constexpr float CaveErosionRange = 0.040f;
static constexpr float CaveWhiteNoise = 0.002f;
static constexpr float CaveAdditiveInputScale = 80.f;
static constexpr float CaveAdditiveOutputScale = 0.45f;
static constexpr float SurfaceCaveShrinkDepth = 100;
static constexpr float SurfaceCaveShrinkFactor = 1.5f;
#pragma endregion
#pragma region Ore Vein Parameters
static constexpr Vector2 ClayVeinHiPassScale = {200.f, 205.f};
static constexpr float ClayVeinHiPassOffset = 0.f;
static constexpr float ClayVeinHiPassOutputScale = 2.2f;
static constexpr float ClayVeinHiPassOffset = 0.f;
static constexpr float ClayVeinHiPassOutputScale = 2.2f;
static constexpr Vector2 ClayVeinLoPassScale = {17.f, 15.f};
static constexpr float ClayVeinLoPassOffset = 420.f;
static constexpr float ClayVeinLoPassOutputScale = 1.2f;
static constexpr float ClayVeinLoPassOffset = 420.f;
static constexpr float ClayVeinLoPassOutputScale = 1.2f;
static constexpr float ClayVeinNoise = 0.175f;
static constexpr float ClayVeinNoise = 0.175f;
static constexpr float ClayVeinRampFactor = 2.f;
static constexpr float ClayVeinRampFactor = 2.f;
static constexpr Vector2 SiltVeinHiPassScale = {220.f, 205.f};
static constexpr float SiltVeinHiPassOffset = 5.f;
static constexpr float SiltVeinHiPassOutputScale = 2.2f;
static constexpr Vector2 SiltVeinLoPassScale = {27.f, 25.f};
static constexpr float SiltVeinLoPassOffset = 422.f;
static constexpr float SiltVeinLoPassOutputScale = 1.25f;
static constexpr float SiltVeinNoise = 0.175f;
static constexpr float SiltVeinRampFactor = 2.f;
static constexpr Vector2 StoneVeinHiPassScale = {30.f, 30.f};
static constexpr float StoneVeinHiPassOffset = 666.f;
static constexpr float StoneVeinHiPassOutputScale = 2.4f;
static constexpr Vector2 StoneVeinLoPassScale = {220.f, 220.f};
static constexpr float StoneVeinLoPassOffset = 0.5f;
static constexpr float StoneVeinLoPassOutputScale = 1.75f;
static constexpr float StoneVeinNoise = 0.25f;
static constexpr float StoneVeinRampFactor = 1.75f;
static constexpr Vector2 DirtVeinHiPassScale = {30.f, 30.f};
static constexpr float DirtVeinHiPassOffset = 12.f;
static constexpr float DirtVeinHiPassOutputScale = 1.35f;
static constexpr Vector2 DirtVeinLoPassScale = {90.f, 90.f};
static constexpr float DirtVeinLoPassOffset = 0.5f;
static constexpr float DirtVeinLoPassOutputScale = 0.75f;
static constexpr float DirtVeinNoise = 0.05f;
static constexpr float DirtVeinRampFactor = 0.5f;
static constexpr Vector2 CoalVeinHiPassScale = {30.f, 30.f};
static constexpr float CoalVeinHiPassOffset = 12.f;
static constexpr float CoalVeinHiPassOutputScale = 1.35f;
static constexpr Vector2 CoalVeinLoPassScale = {90.f, 90.f};
static constexpr float CoalVeinLoPassOffset = 0.5f;
static constexpr float CoalVeinLoPassOutputScale = 0.75f;
static constexpr float CoalVeinNoise = 0.05f;
static constexpr float CoalVeinRampFactor = 0.5f;
static constexpr Vector2 CopperVeinHiPassScale = {30.f, 30.f};
static constexpr float CopperVeinHiPassOffset = 12.f;
static constexpr float CopperVeinHiPassOutputScale = 1.35f;
static constexpr Vector2 CopperVeinLoPassScale = {90.f, 90.f};
static constexpr float CopperVeinLoPassOffset = 0.5f;
static constexpr float CopperVeinLoPassOutputScale = 0.75f;
static constexpr float CopperVeinNoise = 0.05f;
static constexpr float CopperVeinRampFactor = 0.5f;
static constexpr Vector2 TinVeinHiPassScale = {30.f, 30.f};
static constexpr float TinVeinHiPassOffset = 12.f;
static constexpr float TinVeinHiPassOutputScale = 1.35f;
static constexpr Vector2 TinVeinLoPassScale = {90.f, 90.f};
static constexpr float TinVeinLoPassOffset = 0.5f;
static constexpr float TinVeinLoPassOutputScale = 0.75f;
static constexpr float TinVeinNoise = 0.05f;
static constexpr float TinVeinRampFactor = 0.5f;
static constexpr Vector2 IronVeinHiPassScale = {30.f, 30.f};
static constexpr float IronVeinHiPassOffset = 12.f;
static constexpr float IronVeinHiPassOutputScale = 1.35f;
static constexpr Vector2 IronVeinLoPassScale = {90.f, 90.f};
static constexpr float IronVeinLoPassOffset = 0.5f;
static constexpr float IronVeinLoPassOutputScale = 0.75f;
static constexpr float IronVeinNoise = 0.05f;
static constexpr float IronVeinRampFactor = 0.5f;
#pragma endregion
public:
Generator() = default;
@@ -52,8 +140,18 @@ namespace CaveGame::Core
float Octave(int wx, int wy, float hScale, float vScale, float offset, float outputScale, int octaves);
float ComputeHiLoPass(float hi, float lo, float offset);
/// Returns the sum of hi+lo and (hi*lo) / div, resulting in something approximating noise iterated in 2 octaves.
float AddSumAndPartialProduct(float hi, float lo, float div);
TileID HiLoSelect(float pass, float upperBound, float lowerBound, TileID hiSelect, TileID loSelect, TileID fallback);
/// This function returns a floating point number (Usually in the range [-1, 1]) to be used as a condition for
/// whether ores should spawn at this location, given a set of noise parameters.
/// Ores are generated by computing two Perlin Noise passes, taking the sum of adding and multiplying, then adding in random noise.
/// Hi-Pass is used to define macro (larger-scale) features of ore veins, and Lo-Pass adds minor detailing for a more organic appearance.
float ComputeOre(int wx, int wy, const Vector2& hiPass, const Vector2& loPass, float hiOffset, float loOffset,
float hiScale, float loScale, float noise, float ramp);
TileID ComputeTile(int wx, int wy);
void FirstPass(Chunk& chunk);

View File

@@ -17,14 +17,11 @@ namespace CaveGame::Core
{
precomputed_white_noise_2D[x][y] = rng.Float01Incl();
}
}
}
float Generator::ComputeDepth(int wx, int wy)
{
int tile_id = 0;
// this looks almost the same as the octave noise but with significantly less expense?
//float height_map_low_pass = perlin.Noise(wx / HeightMapHighPassScale, 0.f, 0.25f) * HeightMapHighPassAmplitude;
@@ -55,11 +52,6 @@ namespace CaveGame::Core
return perlin.Noise(wx / hScale, wy / vScale, offset) * outputScale;
}
float Generator::Perlin2(int wx, int wy, const Vector2 hiScale, const Vector2 loScale, Vector2 offset, Vector2 outputScale)
{
}
float Generator::Octave(int wx, int wy, float hScale, float vScale, float offset, float outputScale, int octaves) {
float noise = 0;
@@ -78,8 +70,8 @@ namespace CaveGame::Core
float Generator::ComputeHiLoPass(float hi, float lo, float offset) {
return hi + lo + ((hi * lo) / offset);
float Generator::AddSumAndPartialProduct(float hi, float lo, float div) {
return hi + lo + ((hi * lo) / div);
}
TileID Generator::HiLoSelect(float pass, float upperBound, float lowerBound, TileID hiSelect, TileID loSelect, TileID fallback) {
@@ -92,31 +84,28 @@ namespace CaveGame::Core
return fallback;
}
//bool Generator::CaveTest() { }
float Generator::ComputeOre(int wx, int wy, const Vector2& hiPass, const Vector2& loPass, float hiOffset, float loOffset, float hiScale, float loScale, float noise, float ramp)
{
float pass_1 = Perlin(wx, wy, hiPass.x, hiPass.y, hiOffset, hiScale);
float pass_2 = Perlin(wx, wy, loPass.x, loPass.y, loOffset, loScale);
float rng = GetPrecomputedWhiteNoise2D(wx, wy)*noise;
return AddSumAndPartialProduct(pass_1, pass_2, ramp) - rng;
}
//float Generator::ComputeLiquidPool() {}
/// Calculates the tile to be placed at a given x,y coordinates during the first terrain iteration.
TileID Generator::ComputeTile(int wx, int wy) {
float depth = ComputeDepth(wx, wy);
TileID base = HeightMap(depth, wx, wy);
/*float cave_high_sx = 48.f;
float cave_high_sy = 48.f;
float cave_low_sx = 192.f;
float cave_low_sy = 192.f;
float cave_high_pass = perlin.Noise(wx / cave_high_sx, wy / cave_high_sy, 1.f);
float cave_low_pass = perlin.Noise(wx / cave_low_sx, wy / cave_low_sy, 0.5f);
float cave_sum = cave_high_pass + cave_low_pass;
float cave_product = cave_high_pass * cave_low_pass;
if (cave_sum > -0.05f && 0.2f > cave_sum && cave_product > -0.15f && 0.15f > cave_product)
{
return Core::AIR;
} else { return base; }*/
//float cave_erosion = perlin.Noise(wx / CaveInputScale, wy / CaveInputScale, 0.f) * CaveOutputScale;
float cave_erosion = Perlin(wx, wy, CaveInputScale, CaveInputScale, 0.f, CaveOutputScale);
float rng = GetPrecomputedWhiteNoise2D(wx, wy)*0.002;
float rng = GetPrecomputedWhiteNoise2D(wx, wy)*CaveWhiteNoise;
//float cave_addition = perlin.Noise(wx / CaveAdditiveInputScale, wy / CaveAdditiveInputScale, 0.f)*CaveAdditiveOutputScale;
float cave_addition = Perlin(wx, wy, CaveAdditiveInputScale, CaveAdditiveInputScale, 0.25f, CaveAdditiveOutputScale);
@@ -137,49 +126,91 @@ namespace CaveGame::Core
if (depth > 1) {
// Ore computation
float clay_pass_1 = Perlin(wx, wy, ClayVeinHiPassScale.x, ClayVeinHiPassScale.y, ClayVeinHiPassOffset, ClayVeinHiPassOutputScale);
float clay_pass_2 = Perlin(wx, wy, ClayVeinLoPassScale.x, ClayVeinLoPassScale.y, ClayVeinLoPassOffset, ClayVeinLoPassOutputScale);
float clay_rng = GetPrecomputedWhiteNoise2D(wx, wy)*ClayVeinNoise;
float clay_pass = ComputeHiLoPass(clay_pass_1, clay_pass_2, ClayVeinRampFactor) - clay_rng;
// Chunks of clay and dirt.
float clay_pass = ComputeOre(wx, wy, ClayVeinHiPassScale, ClayVeinLoPassScale, ClayVeinHiPassOffset, ClayVeinLoPassOffset,
ClayVeinHiPassOutputScale, ClayVeinLoPassOutputScale, ClayVeinNoise, ClayVeinRampFactor);
// Yes, sometimes we re-use a pass to generate another tile entirely. Why?
// We don't need the full parameter space for clay generation, as it's rarer, and it gives
// more variety to dirt blob generation, for example.
if (clay_pass > 0.85f) { return TileID::CLAY; }
if (clay_pass < -0.75f) { return TileID::DIRT; }
float silt_pass_1 = perlin.Noise(wx / 220.f, wy / 205.f, 5.f) * 2.2f;
float silt_pass_2 = perlin.Noise(wx / 27.f, wy / 25.f, 422.f) * 1.25f;
//float rng = GetPrecomputedWhiteNoise2D(wx, wy)*0.175;
float silt_pass = silt_pass_1 + silt_pass_2 + ((silt_pass_1 * silt_pass_2) / 2.f) - rng;
// Chunks of silt and dirt.
float silt_pass = ComputeOre(wx, wy, SiltVeinHiPassScale, SiltVeinLoPassScale, SiltVeinHiPassOffset, SiltVeinLoPassOffset,
SiltVeinHiPassOutputScale, SiltVeinLoPassOutputScale, SiltVeinNoise, SiltVeinRampFactor);
if (silt_pass > 0.85f) { return TileID::SILT; }
if (silt_pass < -0.75f) { return TileID::DIRT; }
//float stone_pass_1 = perlin.Noise(wx / 30.f, wy / 30.f, 666.f) * 2.4f;
//float stone_pass_2 = perlin.Noise(wx / 220.f, wy / 220.f, 0.5f) * 1.75f;
//float stone_pass = stone_pass_1 + stone_pass_2 + (stone_pass_1 * stone_pass_2 / 1.75f) + (rng*1.5f);
float stone_pass_1 = perlin.Noise(wx / 30.f, wy / 30.f, 666.f) * 2.4f;
float stone_pass_2 = perlin.Noise(wx / 220.f, wy / 220.f, 0.5f) * 1.75f;
float stone_pass = stone_pass_1 + stone_pass_2 + (stone_pass_1 * stone_pass_2 / 1.75f) + (rng*1.5f);
// Chunks of stone.
float stone_pass = ComputeOre(wx, wy, StoneVeinHiPassScale, StoneVeinLoPassScale, StoneVeinHiPassOffset, StoneVeinLoPassOffset,
StoneVeinHiPassOutputScale, StoneVeinLoPassOutputScale, StoneVeinNoise, StoneVeinRampFactor);
// Chunks of stone
if (stone_pass > 0.7f) { return TileID::STONE; }
if (stone_pass < -0.7f) { return TileID::STONE; }
float dirt_pass_1 = perlin.Noise(wx / 30.f, wy / 30.f, 12.f) * 1.35f;
float dirt_pass_2 = perlin.Noise(wx / 90.f, wy / 90.f, 0.5f) * 0.75f;
float dirt_pass = dirt_pass_1 + dirt_pass_2;
//float dirt_pass_1 = perlin.Noise(wx / 30.f, wy / 30.f, 12.f) * 1.35f;
//float dirt_pass_2 = perlin.Noise(wx / 90.f, wy / 90.f, 0.5f) * 0.75f;
//float dirt_pass = dirt_pass_1 + dirt_pass_2;
// Chunks of dirt
if (-0.65 > dirt_pass && dirt_pass < 0.65f) {
return TileID::DIRT;
float dirt_pass = ComputeOre(wx, wy, DirtVeinHiPassScale, DirtVeinLoPassScale, DirtVeinHiPassOffset, DirtVeinLoPassOffset,
DirtVeinHiPassOutputScale, DirtVeinLoPassOutputScale, DirtVeinNoise, DirtVeinRampFactor);
if (-0.65 > dirt_pass && dirt_pass < 0.65f) { return TileID::DIRT; }
// Coal veins
float coal_pass = ComputeOre(wx, wy, CoalVeinHiPassScale, CoalVeinLoPassScale, CoalVeinHiPassOffset, CoalVeinLoPassOffset,
CoalVeinHiPassOutputScale, CoalVeinLoPassOutputScale, CoalVeinNoise, CoalVeinRampFactor);
if (coal_pass > 0.75f) { return TileID::COAL_ORE; }
// Copper ore veins
float copper_pass = ComputeOre(wx, wy, CopperVeinHiPassScale, CopperVeinLoPassScale, CopperVeinHiPassOffset, CopperVeinLoPassOffset,
CopperVeinHiPassOutputScale, CopperVeinLoPassOutputScale, CopperVeinNoise, CopperVeinRampFactor);
if (copper_pass > 0.8f) { return TileID::COPPER_ORE; }
// Tin ore veins
float tin_pass = ComputeOre(wx, wy, TinVeinHiPassScale, TinVeinLoPassScale, TinVeinHiPassOffset, TinVeinLoPassOffset,
TinVeinHiPassOutputScale, TinVeinLoPassOutputScale, TinVeinNoise, TinVeinRampFactor);
if (tin_pass > 0.85) { return TileID::TIN_ORE; }
// Iron ore veins
float iron_pass = ComputeOre(wx, wy, IronVeinHiPassScale, IronVeinLoPassScale, IronVeinHiPassOffset, IronVeinLoPassOffset,
IronVeinHiPassOutputScale, IronVeinLoPassOutputScale, IronVeinNoise, IronVeinRampFactor);
if (depth > 1000) {
// Lead ore veins
// Silver ore veins
// Tungsten ore veins
// Gold ore veins
}
if (depth > 10000) {
// Platinum ore veins
// Cobalt ore veins
// Titanium ore veins
// Uranium ore veins
}