From 78db8f0839777aad17f47cb54a767ed0b97f96cf Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Tue, 2 Jul 2024 20:06:26 +0200 Subject: [PATCH] Interpolate the biome interpolation based on some weights, instead of choosing the closest one. This allows making plateaus without having a ramp (from the other biome interpolation) leading up to it. --- src/server/terrain/biomes.zig | 2 ++ src/server/terrain/mapgen/MapGenV1.zig | 34 ++++++++++++++++++++------ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/server/terrain/biomes.zig b/src/server/terrain/biomes.zig index cb52aee8..8a04db35 100644 --- a/src/server/terrain/biomes.zig +++ b/src/server/terrain/biomes.zig @@ -227,6 +227,7 @@ pub const Biome = struct { minHeight: i32, maxHeight: i32, interpolation: Interpolation, + interpolationWeight: f32, roughness: f32, hills: f32, mountains: f32, @@ -266,6 +267,7 @@ pub const Biome = struct { .hills = json.get(f32, "hills", 0), .mountains = json.get(f32, "mountains", 0), .interpolation = std.meta.stringToEnum(Interpolation, json.get([]const u8, "interpolation", "square")) orelse .square, + .interpolationWeight = @max(json.get(f32, "interpolationWeight", 1), std.math.floatMin(f32)), .caves = json.get(f32, "caves", -0.375), .crystals = json.get(u32, "crystals", 0), .stalagmites = json.get(u32, "stalagmites", 0), diff --git a/src/server/terrain/mapgen/MapGenV1.zig b/src/server/terrain/mapgen/MapGenV1.zig index b058a6ea..91c24747 100644 --- a/src/server/terrain/mapgen/MapGenV1.zig +++ b/src/server/terrain/mapgen/MapGenV1.zig @@ -10,6 +10,8 @@ const noise = terrain.noise; const FractalNoise = noise.FractalNoise; const RandomlyWeightedFractalNoise = noise.RandomlyWeightedFractalNoise; const PerlinNoise = noise.PerlinNoise; +const vec = main.vec; +const Vec2f = vec.Vec2f; pub const id = "cubyz:mapgen_v1"; @@ -22,25 +24,25 @@ pub fn deinit() void { } /// Assumes the 2 points are at tᵢ = (0, 1) -fn interpolationWeights(t: f32, interpolation: terrain.biomes.Interpolation) [2]f32 { +fn interpolationWeights(t: f32, interpolation: terrain.biomes.Interpolation) Vec2f { switch (interpolation) { .none => { if(t < 0.5) { - return [2]f32 {1, 0}; + return .{1, 0}; } else { - return [2]f32 {0, 1}; + return .{0, 1}; } }, .linear => { - return [2]f32 {1 - t, t}; + return .{1 - t, t}; }, .square => { if(t < 0.5) { const tSqr = 2*t*t; - return [2]f32 {1 - tSqr, tSqr}; + return .{1 - tSqr, tSqr}; } else { const tSqr = 2*(1 - t)*(1 - t); - return [2]f32 {tSqr, 1 - tSqr}; + return .{tSqr, 1 - tSqr}; } }, } @@ -113,8 +115,24 @@ pub fn generateMapFragment(map: *MapFragment, worldSeed: u64) void { closestBiome = biomePositions.get(@intCast(xBiome + 1), @intCast(yBiome + 1)).biome; } } - const coefficientsX = interpolationWeights(relXBiome, closestBiome.interpolation); - const coefficientsY = interpolationWeights(relYBiome, closestBiome.interpolation); + const interpolationCoefficientsX = interpolationWeights(relXBiome, .square); + const interpolationCoefficientsY = interpolationWeights(relYBiome, .square); + var coefficientsX: vec.Vec2f = .{0, 0}; + var coefficientsY: vec.Vec2f = .{0, 0}; + var totalWeight: f32 = 0; + for(0..2) |dx| { + for(0..2) |dy| { + const biomeMapX = @as(usize, @intCast(xBiome)) + dx; + const biomeMapY = @as(usize, @intCast(yBiome)) + dy; + const biomeSample = biomePositions.get(biomeMapX, biomeMapY); + const weight = interpolationCoefficientsX[dx]*interpolationCoefficientsY[dy]*biomeSample.biome.interpolationWeight; + coefficientsX += interpolationWeights(relXBiome, biomeSample.biome.interpolation)*@as(Vec2f, @splat(weight)); + coefficientsY += interpolationWeights(relYBiome, biomeSample.biome.interpolation)*@as(Vec2f, @splat(weight)); + totalWeight += weight; + } + } + coefficientsX /= @splat(totalWeight); + coefficientsY /= @splat(totalWeight); for(0..2) |dx| { for(0..2) |dy| { const biomeMapX = @as(usize, @intCast(xBiome)) + dx;