mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-06-18 00:27:02 +08:00
feat: add cave (#8)
* feat: add cave generate * fix: incorrect blocks on cave surface * fix: non-deterministic cave generator * refactor: move all chunk generation to dedicated generation thread * refactor: remove inital cave * feat: add cave parameter adjustment * refactor: adjust cave probability
This commit is contained in:
@@ -46,6 +46,7 @@ private:
|
||||
int m_theme = 0;
|
||||
void show_about_table_bar();
|
||||
void show_biome_table_bar();
|
||||
void show_cave_table_bar();
|
||||
void show_settings_tab_item();
|
||||
void show_world_tab_item();
|
||||
void show_player_tab_item();
|
||||
|
||||
24
include/Cubed/gameplay/cave_carver.hpp
Normal file
24
include/Cubed/gameplay/cave_carver.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/cave_path.hpp"
|
||||
namespace Cubed {
|
||||
class CaveCarver {
|
||||
public:
|
||||
CaveCarver();
|
||||
std::unordered_map<int, CavePath>& paths();
|
||||
void init(unsigned world_seed);
|
||||
void reload(unsigned world_seed);
|
||||
void add_path(const glm::vec3& pos);
|
||||
void try_to_add_path(const ChunkPos& pos, unsigned chunk_seed);
|
||||
void cleanup_finished_caves();
|
||||
|
||||
int cave_sum() const;
|
||||
float& cave_probability();
|
||||
|
||||
private:
|
||||
std::unordered_map<int, CavePath> m_paths;
|
||||
unsigned m_seed = 0;
|
||||
int m_sum = 0;
|
||||
Random m_random;
|
||||
float m_cave_probability = 0.035f;
|
||||
};
|
||||
} // namespace Cubed
|
||||
85
include/Cubed/gameplay/cave_path.hpp
Normal file
85
include/Cubed/gameplay/cave_path.hpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cubed/gameplay/chunk_pos.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);
|
||||
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 = 15.0f;
|
||||
static inline float m_radius_y_min = 4.0f;
|
||||
static inline float m_radius_y_max = 10.0f;
|
||||
static inline float m_delta_angle_min = -5.0f;
|
||||
static inline float m_delta_angle_max = 5.0f;
|
||||
static inline int m_step_min = 10;
|
||||
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
|
||||
@@ -38,7 +38,7 @@ private:
|
||||
|
||||
float frequency = 0.01f;
|
||||
float height = 80;
|
||||
|
||||
unsigned m_seed = 0;
|
||||
void clear_dirty();
|
||||
|
||||
public:
|
||||
@@ -98,6 +98,8 @@ public:
|
||||
void biome(BiomeType b);
|
||||
HeightMapArray& heightmap();
|
||||
std::vector<uint8_t>& blocks();
|
||||
World& world();
|
||||
unsigned seed() const;
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
static void reload();
|
||||
static const unsigned& seed();
|
||||
static void seed(unsigned s);
|
||||
|
||||
unsigned chunk_seed() const;
|
||||
// Generate Biome
|
||||
void assign_chunk_biome();
|
||||
// Adjust Biome
|
||||
@@ -54,7 +54,10 @@ private:
|
||||
std::unique_ptr<BiomeBuilder> m_biome_builder{nullptr};
|
||||
bool is_cur_chunk_ins = false;
|
||||
std::array<BiomeType, 8> m_neighbor_biome;
|
||||
unsigned m_chunk_seed = 0;
|
||||
|
||||
void make_biome_builder();
|
||||
void generate_cave();
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "Cubed/AABB.hpp"
|
||||
#include "Cubed/gameplay/cave_carver.hpp"
|
||||
#include "Cubed/gameplay/chunk.hpp"
|
||||
|
||||
#include <atomic>
|
||||
@@ -45,6 +46,7 @@ private:
|
||||
std::atomic<bool> m_gen_running{false};
|
||||
std::atomic<bool> m_need_gen_chunk{false};
|
||||
std::atomic<bool> m_is_rebuilding{false};
|
||||
std::atomic<bool> m_chunk_gen_finished{false};
|
||||
std::atomic<bool> m_could_gen{true};
|
||||
std::atomic<int> m_rendering_distance{24};
|
||||
std::atomic<float> m_chunk_gen_fraction{0.0f};
|
||||
@@ -53,6 +55,8 @@ private:
|
||||
std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk;
|
||||
std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk_queue;
|
||||
|
||||
CaveCarver m_cave_carcer;
|
||||
|
||||
void init_chunks();
|
||||
|
||||
void gen_chunks_internal();
|
||||
@@ -106,6 +110,8 @@ public:
|
||||
void rendering_distance(int rendering_distance);
|
||||
void start_gen_thread();
|
||||
void stop_gen_thread();
|
||||
|
||||
CaveCarver& cave_carcer();
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
|
||||
@@ -27,6 +27,10 @@ inline uint32_t mix_hash(int32_t a, int32_t b, uint32_t fixed_seed) {
|
||||
|
||||
return h;
|
||||
}
|
||||
inline uint32_t combine_32(uint32_t seed, uint32_t v) {
|
||||
seed ^= v + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
return seed;
|
||||
}
|
||||
} // namespace HASH
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -5,12 +5,14 @@ namespace Cubed {
|
||||
class Random {
|
||||
public:
|
||||
Random();
|
||||
|
||||
Random(unsigned seed);
|
||||
bool random_bool(double probability);
|
||||
std::mt19937& engine();
|
||||
unsigned seed();
|
||||
|
||||
void init(unsigned seed);
|
||||
int random_int(int min, int max);
|
||||
float random_float(float min, float max);
|
||||
|
||||
private:
|
||||
unsigned int m_seed = 0;
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
namespace Cubed {
|
||||
|
||||
namespace Math {
|
||||
|
||||
void extract_frustum_planes(const glm::mat4& mvp_matrix,
|
||||
std::vector<glm::vec4>& planes);
|
||||
}
|
||||
|
||||
float smootherstep(float edge0, float edge1, float x);
|
||||
} // namespace Math
|
||||
|
||||
} // namespace Cubed
|
||||
Reference in New Issue
Block a user