refactor: river (#10)

* fix: correct snowy grass block texture

* refactor: river generation

* fix: water placement error due to interpolation

* perf: improve river naturalness

* feat: add river tab item

* fix: path truncation
This commit is contained in:
zhenyan121
2026-05-23 14:29:41 +08:00
committed by GitHub
parent a54e87dbc6
commit bbf8b4e969
25 changed files with 454 additions and 110 deletions

View File

@@ -47,6 +47,7 @@ private:
void show_about_table_bar();
void show_biome_table_bar();
void show_cave_table_bar();
void show_river_table_bar();
void show_settings_tab_item();
void show_world_tab_item();
void show_player_tab_item();

View File

@@ -12,6 +12,5 @@ public:
protected:
void build_bottom();
void fill_water();
};
} // namespace Cubed

View File

@@ -4,10 +4,10 @@ namespace Cubed {
class CaveCarver {
public:
CaveCarver();
std::unordered_map<int, CavePath>& paths();
std::unordered_map<unsigned, CavePath>& paths();
void init(unsigned world_seed);
void reload(unsigned world_seed);
void add_path(const glm::vec3& pos);
void add_path(const glm::vec3& pos, unsigned chunk_seed);
void try_to_add_path(const ChunkPos& pos, unsigned chunk_seed);
void cleanup_finished_caves();
@@ -15,7 +15,7 @@ public:
float& cave_probability();
private:
std::unordered_map<int, CavePath> m_paths;
std::unordered_map<unsigned, CavePath> m_paths;
unsigned m_seed = 0;
int m_sum = 0;
Random m_random;

View File

@@ -1,47 +1,13 @@
#pragma once
#include "Cubed/gameplay/chunk_pos.hpp"
#include "Cubed/gameplay/path_point.hpp"
#include "Cubed/tools/cubed_random.hpp"
#include <glm/glm.hpp>
#include <unordered_set>
namespace Cubed {
struct PathPoint {
glm::vec3 pos;
glm::vec3 tangent{0.0f, 0.0f, 1.0f};
float rad_xz;
float rad_y;
PathPoint(const glm::vec3& p, float rx, float ry)
: pos(p), rad_xz(rx), rad_y(ry) {}
bool contains(const glm::vec3& other_pos) const {
glm::vec3 to_point = other_pos - pos;
glm::vec3 world_up(0.0f, 1.0f, 0.0f);
glm::vec3 right = glm::normalize(glm::cross(tangent, world_up));
if (glm::length(right) < 0.001f) {
glm::vec3 alt_up(1.0f, 0.0f, 0.0f);
right = glm::normalize(glm::cross(tangent, alt_up));
}
glm::vec3 up = glm::normalize(glm::cross(right, tangent));
float horizontal_dist = glm::dot(to_point, right);
float vertical_dist = glm::dot(to_point, up);
float a = rad_xz;
float b = rad_y;
if (a <= 0.0f || b <= 0.0f)
return false;
float check = (horizontal_dist * horizontal_dist) / (a * a) +
(vertical_dist * vertical_dist) / (b * b);
return check <= 1.0f;
}
};
class CavePath {
public:
CavePath(unsigned int world_seed, int path_id, const glm::vec3& start_pos);

View File

@@ -46,6 +46,7 @@ public:
Random& random();
const std::array<BiomeType, 8>& neighbor_biome() const;
void generate_cave();
void generate_river();
private:
static inline std::atomic<bool> is_init{false};

View File

@@ -0,0 +1,36 @@
#pragma once
#include <glm/glm.hpp>
struct PathPoint {
glm::vec3 pos;
glm::vec3 tangent{0.0f, 0.0f, 1.0f};
float rad_xz;
float rad_y;
PathPoint(const glm::vec3& p, float rx, float ry)
: pos(p), rad_xz(rx), rad_y(ry) {}
bool contains(const glm::vec3& other_pos) const {
glm::vec3 to_point = other_pos - pos;
glm::vec3 world_up(0.0f, 1.0f, 0.0f);
glm::vec3 right = glm::normalize(glm::cross(tangent, world_up));
if (glm::length(right) < 0.001f) {
glm::vec3 alt_up(1.0f, 0.0f, 0.0f);
right = glm::normalize(glm::cross(tangent, alt_up));
}
glm::vec3 up = glm::normalize(glm::cross(right, tangent));
float horizontal_dist = glm::dot(to_point, right);
float vertical_dist = glm::dot(to_point, up);
float a = rad_xz;
float b = rad_y;
if (a <= 0.0f || b <= 0.0f)
return false;
float check = (horizontal_dist * horizontal_dist) / (a * a) +
(vertical_dist * vertical_dist) / (b * b);
return check <= 1.0f;
}
};

View File

@@ -0,0 +1,52 @@
#pragma once
#include "Cubed/gameplay/chunk_pos.hpp"
#include "Cubed/gameplay/path_point.hpp"
#include "Cubed/tools/cubed_random.hpp"
#include <glm/glm.hpp>
#include <unordered_set>
namespace Cubed {
class RiverPath {
public:
RiverPath(unsigned int world_seed, int path_id, const glm::vec3& start_pos);
const std::vector<PathPoint>& points() const;
void clear_chunk(const ChunkPos& pos);
bool is_finished() const;
static float& radius_xz_min();
static float& radius_xz_max();
static float& radius_y_min();
static float& radius_y_max();
static float& delta_angle_min();
static float& delta_angle_max();
static int& step_min();
static int& step_max();
private:
static inline float m_radius_xz_min = 5.0f;
static inline float m_radius_xz_max = 10.0f;
static inline float m_radius_y_min = 4.0f;
static inline float m_radius_y_max = 8.0f;
static inline float m_delta_angle_min = -3.0f;
static inline float m_delta_angle_max = 3.0f;
static inline int m_step_min = 150;
static inline int m_step_max = 400;
int m_path_id = 0;
unsigned int m_seed = 0;
float m_yaw = 0.0f;
float m_pitch = 0.0f;
int m_step = 0;
float m_step_len = 1.0f;
PathPoint m_start_path_point{{0.0f, 0.0f, 0.0f}, 0.0f, 0.0f};
Random m_random;
std::vector<PathPoint> m_points;
std::unordered_set<ChunkPos, ChunkPos::Hash> m_pending_chunks;
void collect_path_points();
void precompute_chunk_coverage();
};
} // namespace Cubed

View File

@@ -0,0 +1,31 @@
#pragma once
#include "Cubed/gameplay/chunk_pos.hpp"
#include "Cubed/gameplay/river.path.hpp"
#include "Cubed/tools/cubed_random.hpp"
#include <glm/glm.hpp>
#include <unordered_map>
namespace Cubed {
class RiverWorm {
public:
RiverWorm();
std::unordered_map<unsigned, RiverPath>& paths();
void init(unsigned world_seed);
void reload(unsigned world_seed);
void add_path(const glm::vec3& pos, unsigned chunk_seed);
void try_to_add_path(const ChunkPos& pos, unsigned chunk_seed);
void cleanup_finished_rivers();
int river_sum() const;
float& river_probability();
private:
std::unordered_map<unsigned, RiverPath> m_paths;
unsigned m_seed = 0;
int m_sum = 0;
Random m_random;
float m_probability = 0.01f;
};
}; // namespace Cubed

View File

@@ -2,6 +2,7 @@
#include "Cubed/AABB.hpp"
#include "Cubed/gameplay/cave_carver.hpp"
#include "Cubed/gameplay/chunk.hpp"
#include "Cubed/gameplay/river_worm.hpp"
#include <atomic>
#include <condition_variable>
@@ -56,19 +57,19 @@ private:
std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk_queue;
CaveCarver m_cave_carcer;
RiverWorm m_river_worm;
void init_chunks();
void gen_chunks_internal();
void sync_player_pos(glm::vec3& player_pos);
void compute_required_chunks(ChunkPosSet& required_chunks);
void compute_required_chunks(ChunkPosSet& required_chunks,
ChunkHashMap& temp_neighbor);
void sync_and_collect_missing_chunks(std::vector<ChunkPos>&,
const ChunkPosSet&);
void
build_neighbor_context_for_new_chunks(ConstChunkMap& new_chunks_neighbor,
ChunkPtrUpdateList& affected_neighbor,
const ChunkUpdateList& new_chunks,
ChunkHashMap& temp_neighbor);
const ChunkUpdateList& new_chunks);
void build_neighbor_context_for_affected_neighbors(ChunkPtrUpdateList&,
ConstChunkMap&);
@@ -112,6 +113,7 @@ public:
void stop_gen_thread();
CaveCarver& cave_carcer();
RiverWorm& river_worm();
};
} // namespace Cubed