feat: heightmap-inputs

This commit is contained in:
MihailRis 2024-10-16 00:38:58 +03:00
parent 5e79bc07e9
commit 59c4e26eda
10 changed files with 76 additions and 14 deletions

View File

@ -1,6 +1,6 @@
[forest] [forest]
parameters = [ parameters = [
{weight=1, value=1}, {weight=1, value=0},
{weight=0.5, value=0.2} {weight=0.5, value=0.2}
] ]
layers = [ layers = [
@ -28,8 +28,8 @@ structures = [
[desert] [desert]
parameters = [ parameters = [
{weight=0.3, value=0}, {weight=1.0, value=1},
{weight=0.1, value=0} {weight=0.5, value=0}
] ]
layers = [ layers = [
{height=6, block="base:sand"}, {height=6, block="base:sand"},
@ -43,8 +43,8 @@ sea-layers = [
[plains] [plains]
parameters = [ parameters = [
{weight=0.6, value=0.5}, {weight=0.8, value=0.5},
{weight=0.6, value=0.5} {weight=0.8, value=0.0}
] ]
layers = [ layers = [
{below-sea-level=false, height=1, block="base:grass_block"}, {below-sea-level=false, height=1, block="base:grass_block"},

View File

@ -43,7 +43,7 @@ function place_structures_wide(x, z, w, d, seed, chunk_height)
return placements return placements
end end
function generate_heightmap(x, y, w, h, seed, s) function generate_heightmap(x, y, w, h, seed, s, inputs)
local umap = Heightmap(w, h) local umap = Heightmap(w, h)
local vmap = Heightmap(w, h) local vmap = Heightmap(w, h)
umap.noiseSeed = seed umap.noiseSeed = seed
@ -65,6 +65,12 @@ function generate_heightmap(x, y, w, h, seed, s)
rivermap:pow(0.15) rivermap:pow(0.15)
rivermap:max(0.5) rivermap:max(0.5)
map:mul(rivermap) map:mul(rivermap)
local desertmap = Heightmap(w, h)
desertmap.noiseSeed = seed
desertmap:cellnoise({x+52, y+326}, 0.3*s, 2, 0.2)
desertmap:add(0.4)
map:mixin(desertmap, inputs[1])
return map return map
end end
@ -72,6 +78,8 @@ function generate_biome_parameters(x, y, w, h, seed, s)
local tempmap = Heightmap(w, h) local tempmap = Heightmap(w, h)
tempmap.noiseSeed = seed + 5324 tempmap.noiseSeed = seed + 5324
tempmap:noise({x, y}, 0.04*s, 6) tempmap:noise({x, y}, 0.04*s, 6)
tempmap:mul(0.5)
tempmap:add(0.5)
local hummap = Heightmap(w, h) local hummap = Heightmap(w, h)
hummap.noiseSeed = seed + 953 hummap.noiseSeed = seed + 953
hummap:noise({x, y}, 0.04*s, 6) hummap:noise({x, y}, 0.04*s, 6)

View File

@ -2,3 +2,4 @@
# 2 - humidity # 2 - humidity
biome-parameters = 2 biome-parameters = 2
sea-level = 64 sea-level = 64
heightmap-inputs = [1]

View File

@ -202,7 +202,20 @@ void ContentLoader::loadGenerator(
map.at("heights-bpd").get(def.heightsBPD); map.at("heights-bpd").get(def.heightsBPD);
map.at("sea-level").get(def.seaLevel); map.at("sea-level").get(def.seaLevel);
map.at("wide-structs-chunks-radius").get(def.wideStructsChunksRadius); map.at("wide-structs-chunks-radius").get(def.wideStructsChunksRadius);
if (map.has("heightmap-inputs")) {
for (const auto& element : map["heightmap-inputs"]) {
int index = element.asInteger();
if (index <= 0 || index > def.biomeParameters) {
throw std::runtime_error(
"invalid biome parameter index " + std::to_string(index));
}
def.heightmapInputs.push_back(index - 1);
}
}
if (!def.heightmapInputs.empty() && def.biomesBPD != def.heightsBPD) {
logger.warning() << "generator has heightmap-inputs but biomes-bpd "
"is not equal to heights-bpd, generator will work slower!";
}
auto folder = generatorsDir / fs::u8path(name + ".files"); auto folder = generatorsDir / fs::u8path(name + ".files");
auto scriptFile = folder / fs::u8path("script.lua"); auto scriptFile = folder / fs::u8path("script.lua");

View File

@ -38,7 +38,11 @@ public:
} }
std::shared_ptr<Heightmap> generateHeightmap( std::shared_ptr<Heightmap> generateHeightmap(
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, uint bpd const glm::ivec2& offset,
const glm::ivec2& size,
uint64_t seed,
uint bpd,
const std::vector<std::shared_ptr<Heightmap>>& inputs
) override { ) override {
pushenv(L, *env); pushenv(L, *env);
if (getfield(L, "generate_heightmap")) { if (getfield(L, "generate_heightmap")) {
@ -46,7 +50,15 @@ public:
pushivec_stack(L, size); pushivec_stack(L, size);
pushinteger(L, seed); pushinteger(L, seed);
pushinteger(L, bpd); pushinteger(L, bpd);
if (call_nothrow(L, 6)) { if (!inputs.empty()) {
size_t inputsNum = def.heightmapInputs.size();
createtable(L, inputsNum, 0);
for (size_t i = 0; i < inputsNum; i++) {
newuserdata<LuaHeightmap>(L, inputs[i]);
rawseti(L, i+1);
}
}
if (call_nothrow(L, 6 + (!inputs.empty()))) {
auto map = touserdata<LuaHeightmap>(L, -1)->getHeightmap(); auto map = touserdata<LuaHeightmap>(L, -1)->getHeightmap();
pop(L, 2); pop(L, 2);
return map; return map;

View File

@ -105,3 +105,9 @@ void Heightmap::crop(
height = dstheight; height = dstheight;
buffer = std::move(dst); buffer = std::move(dst);
} }
void Heightmap::clamp() {
for (uint i = 0; i < width * height; i++) {
buffer[i] = std::min(1.0f, std::max(0.0f, buffer[i]));
}
}

View File

@ -30,6 +30,8 @@ public:
void crop(uint srcX, uint srcY, uint dstWidth, uint dstHeight); void crop(uint srcX, uint srcY, uint dstWidth, uint dstHeight);
void clamp();
uint getWidth() const { uint getWidth() const {
return width; return width;
} }

View File

@ -128,12 +128,14 @@ public:
/// @param size size of the heightmap /// @param size size of the heightmap
/// @param seed world seed /// @param seed world seed
/// @param bpd blocks per dot /// @param bpd blocks per dot
/// @param inputs biome parameter maps passed to generate_heightmap
/// @return generated heightmap (can't be nullptr) /// @return generated heightmap (can't be nullptr)
virtual std::shared_ptr<Heightmap> generateHeightmap( virtual std::shared_ptr<Heightmap> generateHeightmap(
const glm::ivec2& offset, const glm::ivec2& offset,
const glm::ivec2& size, const glm::ivec2& size,
uint64_t seed, uint64_t seed,
uint bpd uint bpd,
const std::vector<std::shared_ptr<Heightmap>>& inputs
) = 0; ) = 0;
/// @brief Generate a biomes parameters maps /// @brief Generate a biomes parameters maps
@ -207,12 +209,15 @@ struct GeneratorDef {
uint biomesBPD = 8; uint biomesBPD = 8;
/// @brief Heightmap blocks per dot /// @brief Heightmap blocks per dot
uint heightsBPD = 4; uint heightsBPD = 8;
/// @brief Number of chunks must be generated before and after wide /// @brief Number of chunks must be generated before and after wide
/// structures placement triggered /// structures placement triggered
uint wideStructsChunksRadius = 3; uint wideStructsChunksRadius = 3;
/// @brief Indices of biome parameter maps passed to generate_heightmap
std::vector<uint8_t> heightmapInputs;
std::unordered_map<std::string, size_t> structuresIndices; std::unordered_map<std::string, size_t> structuresIndices;
std::vector<std::unique_ptr<VoxelStructure>> structures; std::vector<std::unique_ptr<VoxelStructure>> structures;
std::vector<Biome> biomes; std::vector<Biome> biomes;

View File

@ -300,6 +300,16 @@ void WorldGenerator::generateBiomes(
seed, seed,
bpd bpd
); );
for (auto index : def.heightmapInputs) {
// copy non-scaled maps
auto copy = std::make_shared<Heightmap>(*biomeParams[index]);
copy->resize(
floordiv(CHUNK_W, def.heightsBPD) + 1,
floordiv(CHUNK_D, def.heightsBPD) + 1,
InterpolationType::LINEAR
);
prototype.heightmapInputs.push_back(std::move(copy));
}
for (const auto& map : biomeParams) { for (const auto& map : biomeParams) {
map->resize( map->resize(
CHUNK_W + bpd, CHUNK_D + bpd, InterpolationType::LINEAR CHUNK_W + bpd, CHUNK_D + bpd, InterpolationType::LINEAR
@ -330,8 +340,10 @@ void WorldGenerator::generateHeightmap(
{floordiv(chunkX * CHUNK_W, bpd), floordiv(chunkZ * CHUNK_D, bpd)}, {floordiv(chunkX * CHUNK_W, bpd), floordiv(chunkZ * CHUNK_D, bpd)},
{floordiv(CHUNK_W, bpd)+1, floordiv(CHUNK_D, bpd)+1}, {floordiv(CHUNK_W, bpd)+1, floordiv(CHUNK_D, bpd)+1},
seed, seed,
bpd bpd,
prototype.heightmapInputs
); );
prototype.heightmap->clamp();
prototype.heightmap->resize( prototype.heightmap->resize(
CHUNK_W + bpd, CHUNK_D + bpd, InterpolationType::LINEAR CHUNK_W + bpd, CHUNK_D + bpd, InterpolationType::LINEAR
); );
@ -363,9 +375,9 @@ void WorldGenerator::generatePlants(
const Biome* biome = biomes[z * CHUNK_W + x]; const Biome* biome = biomes[z * CHUNK_W + x];
int height = heights[z * CHUNK_W + x] * CHUNK_H; int height = heights[z * CHUNK_W + x] * CHUNK_H;
height = std::max(0, height); height = std::min(std::max(0, height), CHUNK_H-1);
if (height+1 > def.seaLevel) { if (height+1 > def.seaLevel && height+1 < CHUNK_H) {
float rand = plantsRand.randFloat(); float rand = plantsRand.randFloat();
blockid_t plant = biome->plants.choose(rand); blockid_t plant = biome->plants.choose(rand);
if (plant) { if (plant) {

View File

@ -32,6 +32,9 @@ struct ChunkPrototype {
std::shared_ptr<Heightmap> heightmap; std::shared_ptr<Heightmap> heightmap;
std::vector<Placement> placements; std::vector<Placement> placements;
/// @brief biome parameters maps saved until heightmaps generation
std::vector<std::shared_ptr<Heightmap>> heightmapInputs {};
}; };
struct WorldGenDebugInfo { struct WorldGenDebugInfo {