]> git.localhorst.tv Git - blank.git/commitdiff
cutting corners in chunk generation
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 4 Dec 2015 14:44:13 +0000 (15:44 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Fri, 4 Dec 2015 14:44:13 +0000 (15:44 +0100)
like, literally cutting them off, lol

doc/todo
src/world/Generator.cpp
src/world/Generator.hpp

index 21bf7ae708beb3704f35baba438c2ff6241dfd48..4bbfb7dc5930f3874415114c2c8d5c4a1ddd2832 100644 (file)
--- a/doc/todo
+++ b/doc/todo
@@ -103,12 +103,15 @@ world generator that is not boring
        exploration
        biomes seem too small, maybe that will become easier to tune when
        there's a little more diversity between them
+
        chunk generation takes too long, it's incredibly annoying
        should look into speeding it up and executing on a different thread
        compute shaders might be another approach, though that would require
        opengl 4.3, block the gpu, and generally doesn't lend itself well to
        threading (cpu wise). It also requires servers to load GL. maybe not
        such a great idea after all
+       using interpolation between samples of simplex noise now (big thanks
+       to notch ;) ), I'll see how that fares or can be tweaked
 
 spawning
 
index edb7e9caa51bc879ec7181c66153710dc5e24a34..b6d53ae4cf895c189941117bd1e7a9cab7638030 100644 (file)
@@ -49,28 +49,113 @@ void Generator::LoadTypes(const BlockTypeRegistry &reg) {
        candidates.reserve(types.size());
 }
 
+namespace {
+
+struct Interpolation {
+       /// sample points for interpolation
+       /// given coordinates should be the absoloute position of the chunk's (0,0,0) block
+       Interpolation(
+               const SimplexNoise &noise,
+               const glm::vec3 &base,
+               const Generator::Config::NoiseParam &conf
+       ) noexcept {
+               for (int z = 0; z < 5; ++z) {
+                       for (int y = 0; y < 5; ++y) {
+                               for (int x = 0; x < 5; ++x) {
+                                       samples[z][y][x] = OctaveNoise(
+                                               noise,
+                                               base + (glm::vec3(x, y, z) * 4.0f),
+                                               conf.octaves,
+                                               conf.persistence,
+                                               conf.frequency,
+                                               conf.amplitude,
+                                               conf.growth
+                                       );
+                               }
+                       }
+               }
+       }
+       float samples[5][5][5];
+};
+
+struct Parameters {
+       glm::ivec3 a;
+       glm::ivec3 b;
+       glm::ivec3 d;
+};
+
+struct Detail {
+       float humidity;
+       float temperature;
+       float richness;
+       float randomness;
+};
+
+}
+
+struct Generator::ValueField {
+
+       Interpolation solidity;
+       Interpolation humidity;
+       Interpolation temperature;
+       Interpolation richness;
+       Interpolation randomness;
+
+       static Parameters GetParams(const glm::ivec3 &pos) noexcept {
+               Parameters p;
+               p.a = pos / 4;
+               p.b = p.a + 1;
+               p.d = pos % 4;
+               return p;
+       }
+
+       static float Interpolate(const Interpolation &i, const Parameters &p) noexcept {
+               constexpr float A[4] = { 1.0f, 0.75f, 0.5f, 0.25f };
+               constexpr float B[4] = { 0.0f, 0.25f, 0.5f, 0.75f };
+               const float l1[4] = {
+                       i.samples[p.a.z][p.a.y][p.a.x] * A[p.d.x] + i.samples[p.a.z][p.a.y][p.b.x] * B[p.d.x],
+                       i.samples[p.a.z][p.b.y][p.a.x] * A[p.d.x] + i.samples[p.a.z][p.b.y][p.b.x] * B[p.d.x],
+                       i.samples[p.b.z][p.a.y][p.a.x] * A[p.d.x] + i.samples[p.b.z][p.a.y][p.b.x] * B[p.d.x],
+                       i.samples[p.b.z][p.b.y][p.a.x] * A[p.d.x] + i.samples[p.b.z][p.b.y][p.b.x] * B[p.d.x],
+               };
+               const float l2[2] = {
+                       l1[0] * A[p.d.y] + l1[1] * B[p.d.y],
+                       l1[2] * A[p.d.y] + l1[3] * B[p.d.y],
+               };
+               return l2[0] * A[p.d.z] + l2[1] * B[p.d.z];
+       }
+
+};
+
 void Generator::operator ()(Chunk &chunk) const noexcept {
-       ExactLocation::Coarse pos(chunk.Position());
-       ExactLocation::Fine coords(pos * ExactLocation::Extent());
+       ExactLocation::Fine coords(chunk.Position() * ExactLocation::Extent());
+       coords += 0.5f;
+       ValueField field {
+               { solidity_noise, coords, config.solidity },
+               { humidity_noise, coords, config.humidity },
+               { temperature_noise, coords, config.temperature },
+               { richness_noise, coords, config.richness },
+               { random_noise, coords, config.randomness },
+       };
        for (int z = 0; z < Chunk::side; ++z) {
                for (int y = 0; y < Chunk::side; ++y) {
                        for (int x = 0; x < Chunk::side; ++x) {
-                               ExactLocation::Fine block_pos(x, y, z);
-                               chunk.SetBlock(RoughLocation::Fine(x, y, z), Generate(coords + ExactLocation::Fine(x, y, z)));
+                               chunk.SetBlock(RoughLocation::Fine(x, y, z), Generate(field, RoughLocation::Fine(x, y, z)));
                        }
                }
        }
        chunk.SetGenerated();
 }
 
-Block Generator::Generate(const glm::vec3 &pos) const noexcept {
-       float solidity = GetValue(solidity_noise, pos, config.solidity);
+Block Generator::Generate(const ValueField &field, const glm::ivec3 &pos) const noexcept {
+       Parameters params(ValueField::GetParams(pos));
+       float solidity = ValueField::Interpolate(field.solidity, params);
        if (solidity < min_solidity) {
                return Block(0);
        }
-       float humidity = GetValue(humidity_noise, pos, config.humidity);
-       float temperature = GetValue(temperature_noise, pos, config.temperature);
-       float richness = GetValue(richness_noise, pos, config.richness);
+       float humidity = ValueField::Interpolate(field.humidity, params);
+       float temperature = ValueField::Interpolate(field.temperature, params);
+       float richness = ValueField::Interpolate(field.richness, params);
 
        candidates.clear();
        float total = 0.0f;
@@ -90,7 +175,7 @@ Block Generator::Generate(const glm::vec3 &pos) const noexcept {
        if (candidates.empty()) {
                return Block(0);
        }
-       float random = GetValue(random_noise, pos, config.randomness);
+       float random = ValueField::Interpolate(field.randomness, params);
        // as weird as it sounds, but this is faster tham glm::fract and generates a
        // better distribution than (transformed variants of) erf, erfc, atan, and smoothstep
        if (random < 0.0f) random += 1.0f;
@@ -105,20 +190,4 @@ Block Generator::Generate(const glm::vec3 &pos) const noexcept {
        return Block(candidates.back().type->id);
 }
 
-float Generator::GetValue(
-       const SimplexNoise &noise,
-       const glm::vec3 &pos,
-       const Config::NoiseParam &conf
-) noexcept {
-       return OctaveNoise(
-               noise,
-               pos,
-               conf.octaves,
-               conf.persistence,
-               conf.frequency,
-               conf.amplitude,
-               conf.growth
-       );
-}
-
 }
index cf94356a482ccfd2a5e028a83975d027f63c11c9..50b50895d0de59f39924be2a64043dc58fa8aa93 100644 (file)
@@ -42,11 +42,8 @@ public:
        void operator ()(Chunk &) const noexcept;
 
 private:
-       Block Generate(const glm::vec3 &position) const noexcept;
-       static float GetValue(
-               const SimplexNoise &,
-               const glm::vec3 &,
-               const Config::NoiseParam &) noexcept;
+       struct ValueField;
+       Block Generate(const ValueField &, const glm::ivec3 &position) const noexcept;
 
 private:
        const Config &config;