mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-06-18 00:27:02 +08:00
Compare commits
2 Commits
c7a0aff0c1
...
2707748843
| Author | SHA1 | Date | |
|---|---|---|---|
| 2707748843 | |||
| e90b0ce2f4 |
@@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
@@ -13,7 +14,7 @@ constexpr int MAX_CHARACTER = 128;
|
|||||||
constexpr float NORMAL_FOV = 70.0f;
|
constexpr float NORMAL_FOV = 70.0f;
|
||||||
|
|
||||||
constexpr int MAX_BIOME_SUM = 4;
|
constexpr int MAX_BIOME_SUM = 4;
|
||||||
|
using HeightMapArray = std::array<std::array<float, CHUCK_SIZE>, CHUCK_SIZE>;
|
||||||
constexpr float VERTICES_POS[6][6][3] = {
|
constexpr float VERTICES_POS[6][6][3] = {
|
||||||
// ===== front (z = +1) =====
|
// ===== front (z = +1) =====
|
||||||
0.0f, 0.0f, 1.0f, // bottom left
|
0.0f, 0.0f, 1.0f, // bottom left
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
@@ -15,7 +16,8 @@ enum class Biome {
|
|||||||
PLAIN = 0,
|
PLAIN = 0,
|
||||||
FOREST,
|
FOREST,
|
||||||
DESERT,
|
DESERT,
|
||||||
MOUNTAIN
|
MOUNTAIN,
|
||||||
|
NONE
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BiomeHeightRange {
|
struct BiomeHeightRange {
|
||||||
@@ -23,11 +25,16 @@ struct BiomeHeightRange {
|
|||||||
int amplitude;
|
int amplitude;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BiomeNonAdjacent {
|
||||||
|
Biome first;
|
||||||
|
std::vector<Biome> second;
|
||||||
|
Biome replace;
|
||||||
|
};
|
||||||
|
|
||||||
std::string get_biome_str(Biome biome);
|
std::string get_biome_str(Biome biome);
|
||||||
Biome get_biome_from_noise(float temp, float humid);
|
Biome get_biome_from_noise(float temp, float humid);
|
||||||
std::array<float, 3> get_noise_frequencies_for_biome(Biome biome);
|
std::array<float, 3> get_noise_frequencies_for_biome(Biome biome);
|
||||||
BiomeHeightRange get_biome_height_range(Biome biome);
|
BiomeHeightRange get_biome_height_range(Biome biome);
|
||||||
Biome safe_int_to_biome(int x);
|
Biome safe_int_to_biome(int x);
|
||||||
int get_interpolated_height(float world_x, float world_z, float temp, float humid);
|
int get_interpolated_height(float world_x, float world_z, float temp, float humid);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,18 +15,28 @@ class World;
|
|||||||
// if want to use, do init_chunk(), gen_vertex_data() and
|
// if want to use, do init_chunk(), gen_vertex_data() and
|
||||||
class Chunk {
|
class Chunk {
|
||||||
private:
|
private:
|
||||||
|
static constexpr int SIZE_X = CHUCK_SIZE;
|
||||||
|
static constexpr int SIZE_Y = WORLD_SIZE_Y;
|
||||||
|
static constexpr int SIZE_Z = CHUCK_SIZE;
|
||||||
|
|
||||||
|
static inline const std::vector<BiomeNonAdjacent> NON_ADJACENT {{
|
||||||
|
{Biome::PLAIN, {Biome::NONE}, Biome::PLAIN},
|
||||||
|
{Biome::FOREST, {Biome::DESERT}, Biome::PLAIN},
|
||||||
|
{Biome::DESERT, {Biome::MOUNTAIN, Biome::FOREST}, Biome::PLAIN},
|
||||||
|
{Biome::MOUNTAIN, {Biome::DESERT}, Biome::PLAIN}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using HeightMapArray = std::array<std::array<float, SIZE_Z>, SIZE_X>;
|
||||||
std::atomic<bool> m_dirty {false};
|
std::atomic<bool> m_dirty {false};
|
||||||
std::atomic<bool> m_need_upload{true};
|
std::atomic<bool> m_need_upload{true};
|
||||||
std::atomic<bool> m_is_on_gen_vertex_data {false};
|
std::atomic<bool> m_is_on_gen_vertex_data {false};
|
||||||
std::atomic<size_t> m_vertex_sum = 0;
|
std::atomic<size_t> m_vertex_sum = 0;
|
||||||
std::mutex m_vertexs_data_mutex;
|
std::mutex m_vertexs_data_mutex;
|
||||||
static constexpr int SIZE_X = CHUCK_SIZE;
|
|
||||||
static constexpr int SIZE_Y = WORLD_SIZE_Y;
|
|
||||||
static constexpr int SIZE_Z = CHUCK_SIZE;
|
|
||||||
|
|
||||||
Biome m_biome = Biome::PLAIN;
|
std::atomic<Biome> m_biome = Biome::PLAIN;
|
||||||
ChunkPos m_chunk_pos;
|
ChunkPos m_chunk_pos;
|
||||||
World& m_world;
|
World& m_world;
|
||||||
|
HeightMapArray m_heightmap;
|
||||||
// the index is a array of block id
|
// the index is a array of block id
|
||||||
std::vector<uint8_t> m_blocks;
|
std::vector<uint8_t> m_blocks;
|
||||||
GLuint m_vbo = 0;
|
GLuint m_vbo = 0;
|
||||||
@@ -51,10 +61,22 @@ public:
|
|||||||
Biome get_biome() const;
|
Biome get_biome() const;
|
||||||
|
|
||||||
const std::vector<uint8_t>& get_chunk_blocks() const;
|
const std::vector<uint8_t>& get_chunk_blocks() const;
|
||||||
|
HeightMapArray get_heightmap() const;
|
||||||
static int get_index(int x, int y, int z);
|
static int get_index(int x, int y, int z);
|
||||||
static int get_index(const glm::vec3& pos);
|
static int get_index(const glm::vec3& pos);
|
||||||
void init_chunk();
|
void init_chunk();
|
||||||
|
// Generate Biome
|
||||||
|
void gen_phase_one();
|
||||||
|
// Adjust Biome
|
||||||
|
void gen_phase_two(const std::array<const Chunk*, 4>& adj_chunks);
|
||||||
|
// Generate Heightmap
|
||||||
|
void gen_phase_three();
|
||||||
|
// Adjust Height
|
||||||
|
void gen_phase_four(const std::array<std::optional<HeightMapArray>, 4>& neighbor_heightmap);
|
||||||
|
// Generate Block
|
||||||
|
void gen_phase_five();
|
||||||
|
// Generate Structure
|
||||||
|
void gen_phase_six();
|
||||||
//void gen_vertex_data();
|
//void gen_vertex_data();
|
||||||
// 0 : (1, 0)
|
// 0 : (1, 0)
|
||||||
// 1 : (-1, 0)
|
// 1 : (-1, 0)
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ private:
|
|||||||
using ChunkUpdateList = std::vector<std::pair<ChunkPos, Chunk>>;
|
using ChunkUpdateList = std::vector<std::pair<ChunkPos, Chunk>>;
|
||||||
using ConstChunkMap = std::unordered_map<ChunkPos, const Chunk*, ChunkPos::Hash>;
|
using ConstChunkMap = std::unordered_map<ChunkPos, const Chunk*, ChunkPos::Hash>;
|
||||||
using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>;
|
using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>;
|
||||||
|
|
||||||
|
bool m_could_gen = true;
|
||||||
|
|
||||||
glm::vec3 m_gen_player_pos{0.0f, 0.0f, 0.0f};
|
glm::vec3 m_gen_player_pos{0.0f, 0.0f, 0.0f};
|
||||||
std::unordered_map<ChunkPos , Chunk, ChunkPos::Hash> m_chunks;
|
std::unordered_map<ChunkPos , Chunk, ChunkPos::Hash> m_chunks;
|
||||||
std::unordered_map<std::size_t, Player> m_players;
|
std::unordered_map<std::size_t, Player> m_players;
|
||||||
@@ -48,6 +51,8 @@ private:
|
|||||||
std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk;
|
std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk;
|
||||||
std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk_queue;
|
std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk_queue;
|
||||||
|
|
||||||
|
void init_chunks();
|
||||||
|
|
||||||
void gen_chunks_internal();
|
void gen_chunks_internal();
|
||||||
void sync_player_pos(glm::vec3& player_pos);
|
void sync_player_pos(glm::vec3& player_pos);
|
||||||
void compute_required_chunks(ChunkPosSet& required_chunks);
|
void compute_required_chunks(ChunkPosSet& required_chunks);
|
||||||
|
|||||||
@@ -24,10 +24,13 @@ std::string get_biome_str(Biome biome) {
|
|||||||
case MOUNTAIN:
|
case MOUNTAIN:
|
||||||
str = "Mountain";
|
str = "Mountain";
|
||||||
break;
|
break;
|
||||||
|
case NONE:
|
||||||
|
str = "Unknown";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
/*
|
||||||
Biome get_biome_from_noise(float temp, float humid) {
|
Biome get_biome_from_noise(float temp, float humid) {
|
||||||
auto weight = [](float t, float h, float ct, float ch) -> float {
|
auto weight = [](float t, float h, float ct, float ch) -> float {
|
||||||
float dt = t - ct;
|
float dt = t - ct;
|
||||||
@@ -45,7 +48,14 @@ Biome get_biome_from_noise(float temp, float humid) {
|
|||||||
if (w_d >= w_m && w_d >= w_p && w_d >= w_f) return Biome::DESERT;
|
if (w_d >= w_m && w_d >= w_p && w_d >= w_f) return Biome::DESERT;
|
||||||
return Biome::FOREST;
|
return Biome::FOREST;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
Biome get_biome_from_noise(float temp, float humid) {
|
||||||
|
using enum Biome;
|
||||||
|
if (temp < 0.5f && humid < 0.5f) return PLAIN;
|
||||||
|
if (temp < 0.5f && humid >= 0.5f) return FOREST;
|
||||||
|
if (temp >= 0.5f && humid < 0.5f) return DESERT;
|
||||||
|
return MOUNTAIN;
|
||||||
|
}
|
||||||
std::array<float, 3> get_noise_frequencies_for_biome(Biome biome) {
|
std::array<float, 3> get_noise_frequencies_for_biome(Biome biome) {
|
||||||
using enum Biome;
|
using enum Biome;
|
||||||
switch (biome) {
|
switch (biome) {
|
||||||
@@ -57,6 +67,9 @@ std::array<float, 3> get_noise_frequencies_for_biome(Biome biome) {
|
|||||||
return {0.003f, 0.010f, 0.020f};
|
return {0.003f, 0.010f, 0.020f};
|
||||||
case MOUNTAIN:
|
case MOUNTAIN:
|
||||||
return {0.006f, 0.015f, 0.030f};
|
return {0.006f, 0.015f, 0.030f};
|
||||||
|
case NONE:
|
||||||
|
ASSERT_MSG(false, "Chunk Biome is None");
|
||||||
|
throw std::invalid_argument{"Chunk Biome is None"};
|
||||||
}
|
}
|
||||||
Logger::warn("Unknown Biome");
|
Logger::warn("Unknown Biome");
|
||||||
return {0.003f, 0.015f, 0.06f};
|
return {0.003f, 0.015f, 0.06f};
|
||||||
@@ -73,6 +86,9 @@ BiomeHeightRange get_biome_height_range(Biome biome) {
|
|||||||
return {61, 12};
|
return {61, 12};
|
||||||
case MOUNTAIN:
|
case MOUNTAIN:
|
||||||
return {70, 70};
|
return {70, 70};
|
||||||
|
case NONE:
|
||||||
|
ASSERT_MSG(false, "Chunk Biome is None");
|
||||||
|
throw std::invalid_argument{"Chunk Biome is None"};
|
||||||
}
|
}
|
||||||
Logger::warn("Unknown Biome");
|
Logger::warn("Unknown Biome");
|
||||||
return {62, 4};
|
return {62, 4};
|
||||||
|
|||||||
@@ -31,9 +31,10 @@ Chunk::Chunk(Chunk&& other) noexcept :
|
|||||||
m_need_upload(other.m_need_upload.load()),
|
m_need_upload(other.m_need_upload.load()),
|
||||||
m_is_on_gen_vertex_data(other.m_is_on_gen_vertex_data.load()),
|
m_is_on_gen_vertex_data(other.m_is_on_gen_vertex_data.load()),
|
||||||
m_vertex_sum(other.m_vertex_sum.load()),
|
m_vertex_sum(other.m_vertex_sum.load()),
|
||||||
m_biome(other.m_biome),
|
m_biome(other.m_biome.load()),
|
||||||
m_chunk_pos(std::move(other.m_chunk_pos)),
|
m_chunk_pos(std::move(other.m_chunk_pos)),
|
||||||
m_world(other.m_world),
|
m_world(other.m_world),
|
||||||
|
m_heightmap(std::move(other.m_heightmap)),
|
||||||
m_blocks(std::move(other.m_blocks)),
|
m_blocks(std::move(other.m_blocks)),
|
||||||
m_vbo(other.m_vbo),
|
m_vbo(other.m_vbo),
|
||||||
m_vertexs_data(std::move(other.m_vertexs_data))
|
m_vertexs_data(std::move(other.m_vertexs_data))
|
||||||
@@ -42,13 +43,15 @@ Chunk::Chunk(Chunk&& other) noexcept :
|
|||||||
}
|
}
|
||||||
|
|
||||||
Chunk& Chunk::operator=(Chunk&& other) noexcept {
|
Chunk& Chunk::operator=(Chunk&& other) noexcept {
|
||||||
|
//Logger::info("other Chunk pos {} {} in Chunk& Chunk::operator=(Chunk&& other) this {}", other.m_chunk_pos.x, other.m_chunk_pos.z, static_cast<const void*>(&other));
|
||||||
m_vbo = other.m_vbo;
|
m_vbo = other.m_vbo;
|
||||||
other.m_vbo = 0;
|
other.m_vbo = 0;
|
||||||
m_chunk_pos = std::move(other.m_chunk_pos);
|
m_chunk_pos = std::move(other.m_chunk_pos);
|
||||||
|
m_heightmap = std::move(other.m_heightmap);
|
||||||
m_blocks = std::move(other.m_blocks);
|
m_blocks = std::move(other.m_blocks);
|
||||||
m_dirty = other.is_dirty();
|
m_dirty = other.is_dirty();
|
||||||
m_vertexs_data = std::move(other.m_vertexs_data);
|
m_vertexs_data = std::move(other.m_vertexs_data);
|
||||||
m_biome = other.m_biome;
|
m_biome = other.m_biome.load();
|
||||||
m_is_on_gen_vertex_data = other.m_is_on_gen_vertex_data.load();
|
m_is_on_gen_vertex_data = other.m_is_on_gen_vertex_data.load();
|
||||||
m_need_upload = other.m_need_upload.load();
|
m_need_upload = other.m_need_upload.load();
|
||||||
m_vertex_sum = other.m_vertex_sum.load();
|
m_vertex_sum = other.m_vertex_sum.load();
|
||||||
@@ -56,13 +59,18 @@ Chunk& Chunk::operator=(Chunk&& other) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Biome Chunk::get_biome() const {
|
Biome Chunk::get_biome() const {
|
||||||
return m_biome;
|
return m_biome.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<uint8_t>& Chunk::get_chunk_blocks() const{
|
const std::vector<uint8_t>& Chunk::get_chunk_blocks() const{
|
||||||
return m_blocks;
|
return m_blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HeightMapArray Chunk::get_heightmap() const {
|
||||||
|
//Logger::info("Chunk pos {} {} in get_heightmap this {}", m_chunk_pos.x, m_chunk_pos.z, static_cast<const void*>(this));
|
||||||
|
return m_heightmap;
|
||||||
|
}
|
||||||
|
|
||||||
int Chunk::get_index(int x, int y, int z) {
|
int Chunk::get_index(int x, int y, int z) {
|
||||||
ASSERT(!(x < 0 || y < 0 || z < 0 || x >= CHUCK_SIZE || y >= WORLD_SIZE_Y || z >= CHUCK_SIZE));
|
ASSERT(!(x < 0 || y < 0 || z < 0 || x >= CHUCK_SIZE || y >= WORLD_SIZE_Y || z >= CHUCK_SIZE));
|
||||||
if ((x * WORLD_SIZE_Y + y) * CHUCK_SIZE + z < 0 || (x * WORLD_SIZE_Y + y) * CHUCK_SIZE + z >= CHUCK_SIZE * CHUCK_SIZE * WORLD_SIZE_Y) {
|
if ((x * WORLD_SIZE_Y + y) * CHUCK_SIZE + z < 0 || (x * WORLD_SIZE_Y + y) * CHUCK_SIZE + z >= CHUCK_SIZE * CHUCK_SIZE * WORLD_SIZE_Y) {
|
||||||
@@ -209,6 +217,187 @@ void Chunk::init_chunk() {
|
|||||||
resolve_blocks();
|
resolve_blocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Chunk::gen_phase_one() {
|
||||||
|
resolve_biome();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Chunk::gen_phase_two(const std::array<const Chunk*, 4>& adj_chunks) {
|
||||||
|
for (auto& chunk : adj_chunks) {
|
||||||
|
if (chunk == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Biome biome = chunk->get_biome();
|
||||||
|
for (const auto& non : NON_ADJACENT) {
|
||||||
|
if (m_biome != non.first) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (auto b : non.second) {
|
||||||
|
if (b == biome) {
|
||||||
|
m_biome = non.replace;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Chunk::gen_phase_three() {
|
||||||
|
for (int x = 0; x < CHUCK_SIZE; x++) {
|
||||||
|
for (int z = 0; z < CHUCK_SIZE; z++) {
|
||||||
|
|
||||||
|
float world_x = static_cast<float>(x + m_chunk_pos.x * CHUCK_SIZE);
|
||||||
|
float world_z = static_cast<float>(z + m_chunk_pos.z * CHUCK_SIZE);
|
||||||
|
|
||||||
|
auto sample_height = [&](Biome b) -> float {
|
||||||
|
auto range = get_biome_height_range(b);
|
||||||
|
auto [f1, f2, f3] = get_noise_frequencies_for_biome(b);
|
||||||
|
float n =
|
||||||
|
1.00f * PerlinNoise::noise(world_x * f1, 0.5f, world_z * f1) +
|
||||||
|
0.50f * PerlinNoise::noise(world_x * f2, 0.5f, world_z * f2) +
|
||||||
|
0.25f * PerlinNoise::noise(world_x * f3, 0.5f, world_z * f3);
|
||||||
|
n /= 1.75f;
|
||||||
|
return range.base_y + n * range.amplitude;
|
||||||
|
};
|
||||||
|
m_heightmap[x][z] = sample_height(m_biome);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Chunk::gen_phase_four(const std::array<std::optional<HeightMapArray>, 4>& neighbor_heightmap) {
|
||||||
|
// Width of interpolation influence (in number of cells)
|
||||||
|
constexpr int BLEND_RADIUS = 12;
|
||||||
|
|
||||||
|
for (int x = 0; x < SIZE_X; x++) {
|
||||||
|
for (int z = 0; z < SIZE_Z; z++) {
|
||||||
|
float h = static_cast<float>(m_heightmap[x][z]);
|
||||||
|
float total_weight = 1.0f;
|
||||||
|
float blended = h;
|
||||||
|
|
||||||
|
// --- Right neighbor neighbor[0]: (1, 0) ---
|
||||||
|
// Blend when x is close to SIZE_X-1
|
||||||
|
if (neighbor_heightmap[0] != std::nullopt) {
|
||||||
|
int dist = (SIZE_X - 1) - x; // distance from right border
|
||||||
|
if (dist < BLEND_RADIUS) {
|
||||||
|
// Neighbor's boundary row is its x=0 column
|
||||||
|
float neighbor_h = static_cast<float>((*neighbor_heightmap[0])[0][z]);
|
||||||
|
float t = 1.0f - static_cast<float>(dist) / BLEND_RADIUS; // larger weight when closer
|
||||||
|
// Use smoothstep for a more natural transition
|
||||||
|
t = t * t * (3.0f - 2.0f * t);
|
||||||
|
blended += t * neighbor_h;
|
||||||
|
total_weight += t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Left neighbor neighbor[1]: (-1, 0) ---
|
||||||
|
if (neighbor_heightmap[1] != std::nullopt) {
|
||||||
|
int dist = x; // distance from left border
|
||||||
|
if (dist < BLEND_RADIUS) {
|
||||||
|
float neighbor_h = static_cast<float>((*neighbor_heightmap[1])[SIZE_X - 1][z]);
|
||||||
|
float t = 1.0f - static_cast<float>(dist) / BLEND_RADIUS;
|
||||||
|
t = t * t * (3.0f - 2.0f * t);
|
||||||
|
blended += t * neighbor_h;
|
||||||
|
total_weight += t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Front neighbor neighbor[2]: (0, 1) ---
|
||||||
|
if (neighbor_heightmap[2] != std::nullopt) {
|
||||||
|
int dist = (SIZE_Z - 1) - z;
|
||||||
|
if (dist < BLEND_RADIUS) {
|
||||||
|
float neighbor_h = static_cast<float>((*neighbor_heightmap[2])[x][0]);
|
||||||
|
float t = 1.0f - static_cast<float>(dist) / BLEND_RADIUS;
|
||||||
|
t = t * t * (3.0f - 2.0f * t);
|
||||||
|
blended += t * neighbor_h;
|
||||||
|
total_weight += t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Back neighbor neighbor[3]: (0, -1) ---
|
||||||
|
if (neighbor_heightmap[3] != std::nullopt) {
|
||||||
|
int dist = z;
|
||||||
|
if (dist < BLEND_RADIUS) {
|
||||||
|
float neighbor_h = static_cast<float>((*neighbor_heightmap[3])[x][SIZE_Z - 1]);
|
||||||
|
float t = 1.0f - static_cast<float>(dist) / BLEND_RADIUS;
|
||||||
|
t = t * t * (3.0f - 2.0f * t);
|
||||||
|
blended += t * neighbor_h;
|
||||||
|
total_weight += t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_heightmap[x][z] = static_cast<int>(blended / total_weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Chunk::gen_phase_five() {
|
||||||
|
// bottom
|
||||||
|
m_blocks.assign(CHUCK_SIZE * CHUCK_SIZE * WORLD_SIZE_Y, 0);
|
||||||
|
for (int x = 0; x < CHUCK_SIZE; x++) {
|
||||||
|
for (int y = 0; y < 5; y++) {
|
||||||
|
for (int z = 0; z < CHUCK_SIZE; z++) {
|
||||||
|
m_blocks[get_index(x, y, z)] = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int x = 0; x < CHUCK_SIZE; x++) {
|
||||||
|
for (int z = 0; z < CHUCK_SIZE; z++) {
|
||||||
|
int height = static_cast<int>(m_heightmap[x][z]);
|
||||||
|
for (int y = 5; y < height - 5; y++) {
|
||||||
|
m_blocks[get_index(x, y, z)] = 3;
|
||||||
|
}
|
||||||
|
if (m_biome == Biome::MOUNTAIN) {
|
||||||
|
for (int y = height - 5; y <= height - 1; y++) {
|
||||||
|
if (y > 110) {
|
||||||
|
m_blocks[get_index(x, y, z)] = 3;
|
||||||
|
} else {
|
||||||
|
m_blocks[get_index(x, y, z)] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (height > 110) {
|
||||||
|
m_blocks[get_index(x, height - 1, z)] = 3;
|
||||||
|
} else {
|
||||||
|
m_blocks[get_index(x, height - 1, z)] = 1;
|
||||||
|
}
|
||||||
|
} else if (m_biome == Biome::DESERT) {
|
||||||
|
for (int y = height - 5; y <= height; y++) {
|
||||||
|
m_blocks[get_index(x, y, z)] = 4;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int y = height - 5; y <= height - 1; y++) {
|
||||||
|
m_blocks[get_index(x, y, z)] = 2;
|
||||||
|
}
|
||||||
|
for (int y = height; y <= height; y++) {
|
||||||
|
m_blocks[get_index(x, y, z)] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Chunk::gen_phase_six() {
|
||||||
|
if (m_biome == Biome::FOREST) {
|
||||||
|
std::array<int, SIZE_X> x_arr;
|
||||||
|
std::iota(x_arr.begin(), x_arr.end(), 0);
|
||||||
|
std::shuffle(x_arr.begin(), x_arr.end(), Cubed::Random::get().engine());
|
||||||
|
std::array<int, SIZE_Z> z_arr;
|
||||||
|
std::iota(z_arr.begin(), z_arr.end(), 0);
|
||||||
|
std::shuffle(z_arr.begin(), z_arr.end(), Cubed::Random::get().engine());
|
||||||
|
for (auto x : x_arr) {
|
||||||
|
for (auto z : z_arr) {
|
||||||
|
if (Cubed::Random::get().random_bool(0.1)) {
|
||||||
|
build_tree(*this, {x, static_cast<int>(m_heightmap[x][z]), z});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mark_dirty();
|
||||||
|
}
|
||||||
|
|
||||||
void Chunk::upload_to_gpu() {
|
void Chunk::upload_to_gpu() {
|
||||||
|
|
||||||
ASSERT(is_need_upload());
|
ASSERT(is_need_upload());
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
|
|
||||||
static constexpr ChunkPos CHUNK_DIR[] {
|
static constexpr ChunkPos CHUNK_DIR[] {
|
||||||
{1, 0}, {-1, 0}, {0, 1}, {0, -1}
|
{1, 0}, {-1, 0}, {0, 1}, {0, -1}
|
||||||
};
|
};
|
||||||
@@ -75,6 +74,7 @@ Player& World::get_player(const std::string& name){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void World::init_world() {
|
void World::init_world() {
|
||||||
|
m_chunks.reserve(DISTANCE * DISTANCE);
|
||||||
auto t1 = std::chrono::system_clock::now();
|
auto t1 = std::chrono::system_clock::now();
|
||||||
for (int s = 0; s < DISTANCE; s++) {
|
for (int s = 0; s < DISTANCE; s++) {
|
||||||
for (int t = 0; t < DISTANCE; t++) {
|
for (int t = 0; t < DISTANCE; t++) {
|
||||||
@@ -86,28 +86,21 @@ void World::init_world() {
|
|||||||
m_chunks.emplace(pos, Chunk(*this, pos));
|
m_chunks.emplace(pos, Chunk(*this, pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
for (auto& chunk_map : m_chunks) {
|
|
||||||
auto& [chunk_pos, chunk] = chunk_map;
|
|
||||||
chunk.init_chunk();
|
|
||||||
|
|
||||||
}
|
Logger::info("Max Support Thread is {}", std::thread::hardware_concurrency());
|
||||||
// After block gen fininshed
|
init_chunks();
|
||||||
|
auto t2 = std::chrono::system_clock::now();
|
||||||
|
auto d = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
|
||||||
|
Logger::info("Chunk Block Init Finish, Time Consuming: {}", d);
|
||||||
|
// init players
|
||||||
|
m_players.emplace(HASH::str("TestPlayer"), Player(*this, "TestPlayer"));
|
||||||
|
Logger::info("TestPlayer Create Finish");
|
||||||
|
|
||||||
std::array<const std::vector<uint8_t>*, 4> neighbor_block;
|
start_gen_thread();
|
||||||
|
|
||||||
for (auto& [pos, chunk] : m_chunks) {
|
}
|
||||||
for (int i = 0; i < 4; i++) {
|
/*
|
||||||
auto it = m_chunks.find(pos + CHUNK_DIR[i]);
|
void World::init_chunks() {
|
||||||
if (it != m_chunks.end()) {
|
|
||||||
neighbor_block[i] = &(it->second.get_chunk_blocks());
|
|
||||||
} else {
|
|
||||||
neighbor_block[i] = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
chunk.gen_vertex_data(neighbor_block);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
std::vector<Chunk*> chunk_ptrs;
|
std::vector<Chunk*> chunk_ptrs;
|
||||||
chunk_ptrs.reserve(m_chunks.size());
|
chunk_ptrs.reserve(m_chunks.size());
|
||||||
for (auto& [pos, chunk] : m_chunks) {
|
for (auto& [pos, chunk] : m_chunks) {
|
||||||
@@ -148,14 +141,81 @@ void World::init_world() {
|
|||||||
chunk.upload_to_gpu();
|
chunk.upload_to_gpu();
|
||||||
|
|
||||||
}
|
}
|
||||||
auto t2 = std::chrono::system_clock::now();
|
}
|
||||||
auto d = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
|
*/
|
||||||
Logger::info("Chunk Block Init Finish, Time Consuming: {}", d);
|
|
||||||
// init players
|
|
||||||
m_players.emplace(HASH::str("TestPlayer"), Player(*this, "TestPlayer"));
|
|
||||||
Logger::info("TestPlayer Create Finish");
|
|
||||||
|
|
||||||
start_gen_thread();
|
void World::init_chunks() {
|
||||||
|
for (auto& [pos, chunks] : m_chunks) {
|
||||||
|
chunks.gen_phase_one();
|
||||||
|
}
|
||||||
|
std::array<const Chunk*, 4> neighbor_chunks;
|
||||||
|
for (auto& [pos, chunks] : m_chunks) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
auto neighbor_pos = pos + CHUNK_DIR[i];
|
||||||
|
auto it = m_chunks.find(neighbor_pos);
|
||||||
|
if (it == m_chunks.end()) {
|
||||||
|
neighbor_chunks[i] = nullptr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
neighbor_chunks[i] = &it->second;
|
||||||
|
|
||||||
|
}
|
||||||
|
chunks.gen_phase_two(neighbor_chunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [pos, chunks] : m_chunks) {
|
||||||
|
chunks.gen_phase_three();
|
||||||
|
}
|
||||||
|
std::array<std::optional<HeightMapArray>, 4> neighbor_chunk_heightmap;
|
||||||
|
for (auto& [pos, chunks] : m_chunks) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
auto neighbor_pos = pos + CHUNK_DIR[i];
|
||||||
|
auto it = m_chunks.find(neighbor_pos);
|
||||||
|
if (it == m_chunks.end()) {
|
||||||
|
neighbor_chunk_heightmap[i] = std::nullopt;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
neighbor_chunk_heightmap[i] = it->second.get_heightmap();
|
||||||
|
|
||||||
|
}
|
||||||
|
chunks.gen_phase_four(neighbor_chunk_heightmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [pos, chunks] : m_chunks) {
|
||||||
|
chunks.gen_phase_five();
|
||||||
|
chunks.gen_phase_six();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::atomic<int> sync{0};
|
||||||
|
sync.store(1, std::memory_order_release);
|
||||||
|
sync.load(std::memory_order_acquire);
|
||||||
|
|
||||||
|
std::vector<ChunkRenderData> pending_gen_data;
|
||||||
|
pending_gen_data.reserve(m_chunks.size());
|
||||||
|
for (auto& [pos, chunk] : m_chunks) {
|
||||||
|
ChunkRenderData data;
|
||||||
|
data.chunk = &chunk;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
auto it = m_chunks.find(pos + CHUNK_DIR[i]);
|
||||||
|
if (it != m_chunks.end()) {
|
||||||
|
data.neighbor_block[i] = &(it->second.get_chunk_blocks());
|
||||||
|
} else {
|
||||||
|
data.neighbor_block[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pending_gen_data.emplace_back(std::move(data));
|
||||||
|
}
|
||||||
|
std::for_each(std::execution::par, pending_gen_data.begin(), pending_gen_data.end(), [](ChunkRenderData& data){
|
||||||
|
if(!data.chunk) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
data.chunk->gen_vertex_data(data.neighbor_block);
|
||||||
|
});
|
||||||
|
for (auto& chunk_map : m_chunks) {
|
||||||
|
auto& [chunk_pos, chunk] = chunk_map;
|
||||||
|
chunk.upload_to_gpu();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,6 +275,7 @@ void World::gen_chunks_internal() {
|
|||||||
|
|
||||||
Logger::info("New Gen Chunks Sum: {}", need_gen_chunks_pos.size());
|
Logger::info("New Gen Chunks Sum: {}", need_gen_chunks_pos.size());
|
||||||
if (need_gen_chunks_pos.empty()) {
|
if (need_gen_chunks_pos.empty()) {
|
||||||
|
m_could_gen = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ChunkUpdateList new_chunks;
|
ChunkUpdateList new_chunks;
|
||||||
@@ -229,8 +290,49 @@ void World::gen_chunks_internal() {
|
|||||||
|
|
||||||
std::array<const std::vector<uint8_t>*, 4> neighbor_block;
|
std::array<const std::vector<uint8_t>*, 4> neighbor_block;
|
||||||
// build new chunk, but the neighbor in m_chunks also need to re-build
|
// build new chunk, but the neighbor in m_chunks also need to re-build
|
||||||
|
|
||||||
for (auto& [pos, chunk] : new_chunks) {
|
for (auto& [pos, chunk] : new_chunks) {
|
||||||
chunk.init_chunk();
|
chunk.gen_phase_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<const Chunk*, 4> neighbor_chunks;
|
||||||
|
for (auto& [pos, chunks] : new_chunks) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
auto neighbor_pos = pos + CHUNK_DIR[i];
|
||||||
|
auto it = new_chunks_neighbor.find(neighbor_pos);
|
||||||
|
if (it == new_chunks_neighbor.end()) {
|
||||||
|
neighbor_chunks[i] = nullptr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
neighbor_chunks[i] = it->second;
|
||||||
|
|
||||||
|
}
|
||||||
|
chunks.gen_phase_two(neighbor_chunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [pos, chunks] : new_chunks) {
|
||||||
|
chunks.gen_phase_three();
|
||||||
|
}
|
||||||
|
std::array<std::optional<HeightMapArray>, 4> neighbor_chunk_heightmap;
|
||||||
|
for (auto& [pos, chunks] : new_chunks) {
|
||||||
|
{
|
||||||
|
//std::lock_guard lk(m_chunks_mutex);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
auto neighbor_pos = pos + CHUNK_DIR[i];
|
||||||
|
auto it = new_chunks_neighbor.find(neighbor_pos);
|
||||||
|
if (it == new_chunks_neighbor.end()) {
|
||||||
|
neighbor_chunk_heightmap[i] = std::nullopt;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
neighbor_chunk_heightmap[i] = it->second->get_heightmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chunks.gen_phase_four(neighbor_chunk_heightmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& [pos, chunks] : new_chunks) {
|
||||||
|
chunks.gen_phase_five();
|
||||||
|
chunks.gen_phase_six();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& [pos, chunk] : new_chunks) {
|
for (auto& [pos, chunk] : new_chunks) {
|
||||||
@@ -371,6 +473,11 @@ void World::stop_gen_thread() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void World::need_gen() {
|
void World::need_gen() {
|
||||||
|
if (!m_could_gen) {
|
||||||
|
Logger::warn("It is generating or consuming new chunks");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_could_gen = false;
|
||||||
{
|
{
|
||||||
std::lock_guard lk(m_gen_player_pos_mutex);
|
std::lock_guard lk(m_gen_player_pos_mutex);
|
||||||
m_gen_player_pos = get_player("TestPlayer").get_player_pos();
|
m_gen_player_pos = get_player("TestPlayer").get_player_pos();
|
||||||
@@ -509,9 +616,16 @@ void World::update(float delta_time) {
|
|||||||
// unified compute vertex data before rendering
|
// unified compute vertex data before rendering
|
||||||
{
|
{
|
||||||
std::lock_guard lk(m_chunks_mutex);
|
std::lock_guard lk(m_chunks_mutex);
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
for (auto& x : m_new_chunk) {
|
for (auto& x : m_new_chunk) {
|
||||||
m_chunks.insert_or_assign(x.first, std::move(x.second));
|
m_chunks.insert_or_assign(x.first, std::move(x.second));
|
||||||
|
consumed = true;
|
||||||
}
|
}
|
||||||
|
if (consumed) {
|
||||||
|
m_could_gen = true;
|
||||||
|
}
|
||||||
|
|
||||||
m_render_snapshots.clear();
|
m_render_snapshots.clear();
|
||||||
for (auto& [pos, chunk] : m_chunks) {
|
for (auto& [pos, chunk] : m_chunks) {
|
||||||
if (chunk.is_dirty()) {
|
if (chunk.is_dirty()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user