mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-06-17 16:17:02 +08:00
refactor: use fBM for heightmap generation
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
namespace Cubed {
|
||||
|
||||
constexpr float BIOME_NOISE_FREQUENCY = 0.03f;
|
||||
|
||||
constexpr float HEIGHTMAP_NOISE_FREQUENCY = 0.001f;
|
||||
enum class BiomeType { PLAIN = 0, FOREST, DESERT, MOUNTAIN, RIVER, NONE };
|
||||
|
||||
struct BiomeHeightRange {
|
||||
|
||||
@@ -48,12 +48,21 @@ public:
|
||||
Chunk(Chunk&&) noexcept;
|
||||
Chunk& operator=(Chunk&&) noexcept;
|
||||
|
||||
static std::tuple<int, int, int> world_to_block(int world_x, int world_y,
|
||||
int world_z, int chunk_x,
|
||||
int chunk_z);
|
||||
static std::tuple<int, int, int> world_to_block(const glm::ivec3& block_pos,
|
||||
ChunkPos chunk_pos);
|
||||
static std::tuple<int, int, int> block_to_world(int x, int y, int z,
|
||||
int chunk_x, int chunk_z);
|
||||
static std::tuple<int, int, int> block_to_world(const glm::ivec3& block_pos,
|
||||
ChunkPos chunk_pos);
|
||||
BiomeType get_biome() const;
|
||||
ChunkPos get_chunk_pos() const;
|
||||
const std::vector<BlockType>& get_chunk_blocks() const;
|
||||
HeightMapArray get_heightmap() const;
|
||||
static int get_index(int x, int y, int z);
|
||||
static int get_index(const glm::vec3& pos);
|
||||
static int index(int x, int y, int z);
|
||||
static int index(const glm::vec3& pos);
|
||||
// Init Chunk
|
||||
// Determine biome from temperature and humidity noise
|
||||
void gen_phase_one();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
namespace Cubed {
|
||||
|
||||
class PerlinNoise {
|
||||
class PerlinNoise3D {
|
||||
public:
|
||||
static void init(unsigned seed);
|
||||
static float noise(float x, float y, float z);
|
||||
@@ -18,4 +18,19 @@ private:
|
||||
static float grad(int hash, float x, float y, float z);
|
||||
};
|
||||
|
||||
class PerlinNoise2D {
|
||||
public:
|
||||
static void init(unsigned seed);
|
||||
static float noise(float x, float y);
|
||||
static void reload(unsigned seed);
|
||||
|
||||
private:
|
||||
static inline std::atomic<bool> is_init = false;
|
||||
static inline std::vector<int> p;
|
||||
|
||||
static float fade(float t);
|
||||
static float lerp(float t, float a, float b);
|
||||
static float grad(int hash, float x, float y);
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -10,7 +10,7 @@ void BiomeBuilder::build_bottom() {
|
||||
for (int x = 0; x < CHUNK_SIZE; x++) {
|
||||
for (int y = 0; y < 5; y++) {
|
||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
||||
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ void BiomeBuilder::fill_water() {
|
||||
}
|
||||
int height = heightmap[x][z];
|
||||
for (int y = height; y < SEA_LEVEL; y++) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 7;
|
||||
m_blocks[Chunk::index(x, y, z)] = 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@ void DesertBuilder::build_blocks() {
|
||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||
int height = static_cast<int>(m_heightmap[x][z]);
|
||||
for (int y = 5; y < height - 5; y++) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
||||
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||
}
|
||||
|
||||
for (int y = height - 5; y <= height; y++) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 4;
|
||||
m_blocks[Chunk::index(x, y, z)] = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,12 +23,12 @@ void ForestBuilder::build_blocks() {
|
||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||
int height = static_cast<int>(m_heightmap[x][z]);
|
||||
for (int y = 5; y < height - 5; y++) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
||||
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||
}
|
||||
for (int y = height - 5; y < height; y++) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 2;
|
||||
m_blocks[Chunk::index(x, y, z)] = 2;
|
||||
}
|
||||
m_blocks[Chunk::get_index(x, height, z)] = 1;
|
||||
m_blocks[Chunk::index(x, height, z)] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,19 +19,19 @@ void MountainBuilder::build_blocks() {
|
||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||
int height = static_cast<int>(m_heightmap[x][z]);
|
||||
for (int y = 5; y < height - 5; y++) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
||||
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||
}
|
||||
for (int y = height - 5; y <= height - 1; y++) {
|
||||
if (y > 110) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
||||
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||
} else {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 2;
|
||||
m_blocks[Chunk::index(x, y, z)] = 2;
|
||||
}
|
||||
}
|
||||
if (height > 110) {
|
||||
m_blocks[Chunk::get_index(x, height, z)] = 3;
|
||||
m_blocks[Chunk::index(x, height, z)] = 3;
|
||||
} else {
|
||||
m_blocks[Chunk::get_index(x, height, z)] = 1;
|
||||
m_blocks[Chunk::index(x, height, z)] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,12 +19,12 @@ void PlainBuilder::build_blocks() {
|
||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||
int height = static_cast<int>(m_heightmap[x][z]);
|
||||
for (int y = 5; y < height - 5; y++) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
||||
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||
}
|
||||
for (int y = height - 5; y < height; y++) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 2;
|
||||
m_blocks[Chunk::index(x, y, z)] = 2;
|
||||
}
|
||||
m_blocks[Chunk::get_index(x, height, z)] = 1;
|
||||
m_blocks[Chunk::index(x, height, z)] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,16 +19,16 @@ void RiverBuilder::build_blocks() {
|
||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||
int height = static_cast<int>(m_heightmap[x][z]);
|
||||
for (int y = 5; y < height - 5; y++) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 3;
|
||||
m_blocks[Chunk::index(x, y, z)] = 3;
|
||||
}
|
||||
for (int y = height - 5; y <= height - 1; y++) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 2;
|
||||
m_blocks[Chunk::index(x, y, z)] = 2;
|
||||
}
|
||||
for (int y = height; y <= height; y++) {
|
||||
if (y >= SEA_LEVEL - 1) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 1;
|
||||
m_blocks[Chunk::index(x, y, z)] = 1;
|
||||
} else {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 2;
|
||||
m_blocks[Chunk::index(x, y, z)] = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ void RiverBuilder::build_vegetation() {
|
||||
continue;
|
||||
}
|
||||
for (int y = height + 1; y < SEA_LEVEL; y++) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = 7;
|
||||
m_blocks[Chunk::index(x, y, z)] = 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,35 @@ Chunk& Chunk::operator=(Chunk&& other) noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::tuple<int, int, int> Chunk::world_to_block(int world_x, int world_y,
|
||||
int world_z, int chunk_x,
|
||||
int chunk_z) {
|
||||
int x, y, z;
|
||||
y = world_y;
|
||||
x = world_x - chunk_x * CHUNK_SIZE;
|
||||
z = world_z - chunk_z * CHUNK_SIZE;
|
||||
return {x, y, z};
|
||||
}
|
||||
|
||||
std::tuple<int, int, int> Chunk::world_to_block(const glm::ivec3& block_pos,
|
||||
ChunkPos chunk_pos) {
|
||||
return world_to_block(block_pos.x, block_pos.y, block_pos.z, chunk_pos.x,
|
||||
chunk_pos.z);
|
||||
}
|
||||
|
||||
std::tuple<int, int, int> Chunk::block_to_world(int x, int y, int z,
|
||||
int chunk_x, int chunk_z) {
|
||||
int world_x = x + chunk_x * CHUNK_SIZE;
|
||||
int world_z = z + chunk_z * CHUNK_SIZE;
|
||||
int world_y = y;
|
||||
return {world_x, world_y, world_z};
|
||||
}
|
||||
std::tuple<int, int, int> Chunk::block_to_world(const glm::ivec3& block_pos,
|
||||
ChunkPos chunk_pos) {
|
||||
return block_to_world(block_pos.x, block_pos.y, block_pos.z, chunk_pos.x,
|
||||
chunk_pos.z);
|
||||
}
|
||||
|
||||
BiomeType Chunk::get_biome() const { return m_biome.load(); }
|
||||
|
||||
ChunkPos Chunk::get_chunk_pos() const { return m_chunk_pos; }
|
||||
@@ -61,7 +90,7 @@ HeightMapArray Chunk::get_heightmap() const {
|
||||
return m_heightmap;
|
||||
}
|
||||
|
||||
int Chunk::get_index(int x, int y, int z) {
|
||||
int Chunk::index(int x, int y, int z) {
|
||||
ASSERT(!(x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
|
||||
z >= CHUNK_SIZE));
|
||||
if ((x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z < 0 ||
|
||||
@@ -73,8 +102,8 @@ int Chunk::get_index(int x, int y, int z) {
|
||||
return (x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z;
|
||||
}
|
||||
|
||||
int Chunk::get_index(const glm::vec3& pos) {
|
||||
return Chunk::get_index(pos.x, pos.y, pos.z);
|
||||
int Chunk::index(const glm::vec3& pos) {
|
||||
return Chunk::index(pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
void Chunk::gen_vertex_data(
|
||||
@@ -95,7 +124,7 @@ void Chunk::gen_vertex_data(
|
||||
int world_x = x + m_chunk_pos.x * CHUNK_SIZE;
|
||||
int world_z = z + m_chunk_pos.z * CHUNK_SIZE;
|
||||
int world_y = y;
|
||||
int cur_id = m_blocks[get_index(x, y, z)];
|
||||
int cur_id = m_blocks[index(x, y, z)];
|
||||
// air
|
||||
if (cur_id == 0) {
|
||||
continue;
|
||||
@@ -132,7 +161,7 @@ void Chunk::gen_vertex_data(
|
||||
return false;
|
||||
}
|
||||
|
||||
int idx = Chunk::get_index(x, y, z);
|
||||
int idx = Chunk::index(x, y, z);
|
||||
// not init
|
||||
if (static_cast<size_t>(idx) >=
|
||||
chunk_blocks->size()) {
|
||||
@@ -164,7 +193,7 @@ void Chunk::gen_vertex_data(
|
||||
// neighbor_cull = m_world.is_block(glm::ivec3(world_x,
|
||||
// world_y, world_z) + DIR[face]);
|
||||
} else {
|
||||
auto id = m_blocks[get_index(nx, ny, nz)];
|
||||
auto id = m_blocks[index(nx, ny, nz)];
|
||||
if (!is_in_transparent_map(id)) {
|
||||
neighbor_cull = true;
|
||||
} else {
|
||||
@@ -242,7 +271,8 @@ void Chunk::gen_phase_four(
|
||||
Logger::error("ChunkGenerator is Nullptr");
|
||||
return;
|
||||
}
|
||||
m_generator->blend_heightmap_boundaries(neighbor_heightmap, neighbor_biome);
|
||||
// m_generator->blend_heightmap_boundaries(neighbor_heightmap,
|
||||
// neighbor_biome);
|
||||
}
|
||||
|
||||
void Chunk::gen_phase_five() {
|
||||
|
||||
@@ -27,7 +27,8 @@ void ChunkGenerator::init() {
|
||||
std::random_device d;
|
||||
m_generator_seed = d();
|
||||
Logger::info("Chunk Generator Seed {}", m_generator_seed);
|
||||
PerlinNoise::init(m_generator_seed);
|
||||
PerlinNoise3D::init(m_generator_seed);
|
||||
PerlinNoise2D::init(m_generator_seed);
|
||||
is_init = true;
|
||||
}
|
||||
|
||||
@@ -35,7 +36,7 @@ void ChunkGenerator::reload() {
|
||||
if (!is_seed_change) {
|
||||
return;
|
||||
}
|
||||
PerlinNoise::reload(m_generator_seed);
|
||||
PerlinNoise3D::reload(m_generator_seed);
|
||||
is_seed_change = false;
|
||||
}
|
||||
|
||||
@@ -54,10 +55,10 @@ void ChunkGenerator::assign_chunk_biome() {
|
||||
auto m_chunk_pos = m_chunk.chunk_pos();
|
||||
float x = static_cast<float>(m_chunk_pos.x);
|
||||
float z = static_cast<float>(m_chunk_pos.z);
|
||||
float temp = PerlinNoise::noise(x * BIOME_NOISE_FREQUENCY, 0.0f,
|
||||
z * BIOME_NOISE_FREQUENCY);
|
||||
float humid = PerlinNoise::noise(x * BIOME_NOISE_FREQUENCY, 1.0f,
|
||||
z * BIOME_NOISE_FREQUENCY);
|
||||
float temp = PerlinNoise3D::noise(x * BIOME_NOISE_FREQUENCY, 0.0f,
|
||||
z * BIOME_NOISE_FREQUENCY);
|
||||
float humid = PerlinNoise3D::noise(x * BIOME_NOISE_FREQUENCY, 1.0f,
|
||||
z * BIOME_NOISE_FREQUENCY);
|
||||
auto biome = get_biome_from_noise(temp, humid);
|
||||
m_chunk.biome(biome);
|
||||
}
|
||||
@@ -86,6 +87,7 @@ void ChunkGenerator::resolve_biome_adjacency_conflict(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void ChunkGenerator::generate_heightmap() {
|
||||
|
||||
auto m_chunk_pos = m_chunk.chunk_pos();
|
||||
@@ -114,6 +116,37 @@ void ChunkGenerator::generate_heightmap() {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void ChunkGenerator::generate_heightmap() {
|
||||
auto chunk_pos = m_chunk.chunk_pos();
|
||||
auto& heightmap = m_chunk.heightmap();
|
||||
|
||||
for (int x = 0; x < CHUNK_SIZE; ++x) {
|
||||
for (int z = 0; z < CHUNK_SIZE; ++z) {
|
||||
float world_x = static_cast<float>(x + chunk_pos.x * CHUNK_SIZE);
|
||||
float world_z = static_cast<float>(z + chunk_pos.z * CHUNK_SIZE);
|
||||
|
||||
auto fbm_height = [](float x, float y, int octaves,
|
||||
float lacunarity, float gain, float amplitude,
|
||||
float frequency) -> float {
|
||||
float value = 0.0f;
|
||||
for (int i = 0; i < octaves; i++) {
|
||||
value += amplitude *
|
||||
PerlinNoise2D::noise(x * frequency, y * frequency);
|
||||
frequency *= lacunarity;
|
||||
amplitude *= gain;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
int octaves = 4;
|
||||
float lacunarity = 2.0f;
|
||||
float gain = 0.5f;
|
||||
heightmap[x][z] = 64 + fbm_height(world_x, world_z, octaves,
|
||||
lacunarity, gain, 40, 0.005f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkGenerator::blend_heightmap_boundaries(
|
||||
const std::array<std::optional<HeightMapArray>, 8>& neighbor_heightmap,
|
||||
@@ -379,8 +412,8 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
||||
int nx, int nz) -> BlockType {
|
||||
// Search from topmost y downwards for the first non-zero block
|
||||
for (int y = WORLD_HEIGHT - 1; y >= 0; --y) {
|
||||
int idx = Chunk::get_index(
|
||||
nx, y, nz); // linear index: y * area + z * size + x
|
||||
int idx = Chunk::index(nx, y,
|
||||
nz); // linear index: y * area + z * size + x
|
||||
if (idx >= 0 && idx < static_cast<int>(blocks.size()) &&
|
||||
blocks[idx] != 0) {
|
||||
return blocks[idx];
|
||||
@@ -396,7 +429,7 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
||||
BlockType type_self = 0;
|
||||
int top_y = -1;
|
||||
top_y = m_heightmap[x][z];
|
||||
type_self = m_blocks[Chunk::get_index(x, top_y, z)];
|
||||
type_self = m_blocks[Chunk::index(x, top_y, z)];
|
||||
|
||||
if (top_y == -1)
|
||||
continue; // no block? skip
|
||||
@@ -470,7 +503,7 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
||||
final_type = 2;
|
||||
}
|
||||
|
||||
m_blocks[Chunk::get_index(x, top_y, z)] = final_type;
|
||||
m_blocks[Chunk::index(x, top_y, z)] = final_type;
|
||||
// bottom block
|
||||
unsigned fill_type = 2;
|
||||
if (final_type == 1) {
|
||||
@@ -479,7 +512,7 @@ void ChunkGenerator::blend_surface_blocks_borders(
|
||||
fill_type = 4;
|
||||
}
|
||||
for (int y = top_y - 5; y < top_y; y++) {
|
||||
m_blocks[Chunk::get_index(x, y, z)] = fill_type;
|
||||
m_blocks[Chunk::index(x, y, z)] = fill_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -564,7 +597,7 @@ void ChunkGenerator::generate_cave() {
|
||||
if (y == 0) {
|
||||
continue;
|
||||
}
|
||||
blocks[Chunk::get_index(x, y, z)] = 0;
|
||||
blocks[Chunk::index(x, y, z)] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ static constexpr std::array<TreeStructNode, 62> TREE{{
|
||||
bool build_tree(Chunk& chunk, const glm::ivec3& pos) {
|
||||
auto& block = chunk.get_chunk_blocks();
|
||||
|
||||
if (block[Chunk::get_index(pos)] != 1) {
|
||||
if (block[Chunk::index(pos)] != 1) {
|
||||
Logger::info("Root is not Grass Block");
|
||||
return false;
|
||||
}
|
||||
@@ -43,13 +43,13 @@ bool build_tree(Chunk& chunk, const glm::ivec3& pos) {
|
||||
z >= CHUNK_SIZE) {
|
||||
return false;
|
||||
}
|
||||
if (block[Chunk::get_index(tree_node)] != 0) {
|
||||
if (block[Chunk::index(tree_node)] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto& d : TREE) {
|
||||
auto tree_node = pos + d.offset;
|
||||
chunk.set_chunk_block(Chunk::get_index(tree_node), d.id);
|
||||
chunk.set_chunk_block(Chunk::index(tree_node), d.id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ void World::init_chunks() {
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void World::init_chunks() {
|
||||
|
||||
@@ -332,6 +333,8 @@ ChunkPos World::chunk_pos(int world_x, int world_z) {
|
||||
return {chunk_x, chunk_z};
|
||||
}
|
||||
|
||||
#pragma region ChunkGenerate
|
||||
|
||||
void World::gen_chunks_internal() {
|
||||
m_chunk_gen_fraction = 0.0f;
|
||||
m_chunk_gen_finished = false;
|
||||
@@ -597,6 +600,8 @@ void World::build_neighbor_context_for_affected_neighbors(
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
void World::start_gen_thread() {
|
||||
m_gen_running = true;
|
||||
Logger::info("Gen Thread Started");
|
||||
@@ -667,15 +672,12 @@ int World::get_block(const glm::ivec3& block_pos) const {
|
||||
}
|
||||
|
||||
const auto& chunk_blocks = it->second.get_chunk_blocks();
|
||||
int x, y, z;
|
||||
y = block_pos.y;
|
||||
x = block_pos.x - chunk_x * CHUNK_SIZE;
|
||||
z = block_pos.z - chunk_z * CHUNK_SIZE;
|
||||
auto [x, y, z] = Chunk::world_to_block(block_pos, {chunk_x, chunk_z});
|
||||
if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
|
||||
z >= CHUNK_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
return chunk_blocks[Chunk::get_index(x, y, z)];
|
||||
return chunk_blocks[Chunk::index(x, y, z)];
|
||||
}
|
||||
|
||||
bool World::is_block(const glm::ivec3& block_pos) const {
|
||||
@@ -687,15 +689,12 @@ bool World::is_block(const glm::ivec3& block_pos) const {
|
||||
return false;
|
||||
}
|
||||
const auto& chunk_blocks = it->second.get_chunk_blocks();
|
||||
int x, y, z;
|
||||
y = block_pos.y;
|
||||
x = block_pos.x - chunk_x * CHUNK_SIZE;
|
||||
z = block_pos.z - chunk_z * CHUNK_SIZE;
|
||||
auto [x, y, z] = Chunk::world_to_block(block_pos, {chunk_x, chunk_z});
|
||||
if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
|
||||
z >= CHUNK_SIZE) {
|
||||
return false;
|
||||
}
|
||||
auto id = chunk_blocks[Chunk::get_index(x, y, z)];
|
||||
auto id = chunk_blocks[Chunk::index(x, y, z)];
|
||||
if (id == 0) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -718,16 +717,14 @@ void World::set_block(const glm::ivec3& block_pos, unsigned id) {
|
||||
return;
|
||||
}
|
||||
|
||||
int x, y, z;
|
||||
y = world_y;
|
||||
x = world_x - chunk_x * CHUNK_SIZE;
|
||||
z = world_z - chunk_z * CHUNK_SIZE;
|
||||
auto [x, y, z] =
|
||||
Chunk::world_to_block(world_x, world_y, world_z, chunk_x, chunk_z);
|
||||
if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
|
||||
z >= CHUNK_SIZE) {
|
||||
return;
|
||||
}
|
||||
|
||||
it->second.set_chunk_block(Chunk::get_index(x, y, z), id);
|
||||
it->second.set_chunk_block(Chunk::index(x, y, z), id);
|
||||
|
||||
static const glm::ivec3 NEIGHBOR_DIRS[] = {
|
||||
{1, 0, 0}, {-1, 0, 0}, {0, 0, -1}, {0, 0, 1}};
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "Cubed/tools/perlin_noise.hpp"
|
||||
|
||||
#include "Cubed/config.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/cubed_random.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
@@ -10,7 +8,7 @@
|
||||
|
||||
namespace Cubed {
|
||||
|
||||
void PerlinNoise::init(unsigned seed) {
|
||||
void PerlinNoise3D::init(unsigned seed) {
|
||||
p.resize(256);
|
||||
std::iota(p.begin(), p.end(), 0);
|
||||
Logger::info("Init Perlin Noise With Seed {}", seed);
|
||||
@@ -20,7 +18,7 @@ void PerlinNoise::init(unsigned seed) {
|
||||
is_init = true;
|
||||
}
|
||||
|
||||
float PerlinNoise::noise(float x, float y, float z) {
|
||||
float PerlinNoise3D::noise(float x, float y, float z) {
|
||||
ASSERT_MSG(is_init, "The PerlinNoise don't init!");
|
||||
int ix = static_cast<int>(std::floor(x)) & 255;
|
||||
int iy = static_cast<int>(std::floor(y)) & 255;
|
||||
@@ -55,11 +53,13 @@ float PerlinNoise::noise(float x, float y, float z) {
|
||||
return (res + 1.0f) / 2.0f;
|
||||
}
|
||||
|
||||
float PerlinNoise::fade(float t) { return t * t * t * (t * (t * 6 - 15) + 10); }
|
||||
float PerlinNoise3D::fade(float t) {
|
||||
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||
}
|
||||
|
||||
float PerlinNoise::lerp(float t, float a, float b) { return a + t * (b - a); }
|
||||
float PerlinNoise3D::lerp(float t, float a, float b) { return a + t * (b - a); }
|
||||
|
||||
float PerlinNoise::grad(int hash, float x, float y, float z) {
|
||||
float PerlinNoise3D::grad(int hash, float x, float y, float z) {
|
||||
int h = hash & 15;
|
||||
|
||||
float u = h < 8 ? x : y;
|
||||
@@ -68,7 +68,7 @@ float PerlinNoise::grad(int hash, float x, float y, float z) {
|
||||
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
||||
}
|
||||
|
||||
void PerlinNoise::reload(unsigned seed) {
|
||||
void PerlinNoise3D::reload(unsigned seed) {
|
||||
is_init = false;
|
||||
p.resize(256);
|
||||
std::iota(p.begin(), p.end(), 0);
|
||||
@@ -79,4 +79,59 @@ void PerlinNoise::reload(unsigned seed) {
|
||||
is_init = true;
|
||||
}
|
||||
|
||||
void PerlinNoise2D::init(unsigned seed) {
|
||||
p.resize(256);
|
||||
std::iota(p.begin(), p.end(), 0);
|
||||
Logger::info("Init Perlin Noise With Seed {}", seed);
|
||||
std::shuffle(p.begin(), p.end(), std::mt19937(seed));
|
||||
|
||||
p.insert(p.end(), p.begin(), p.end()); // 扩展到 512,方便索引
|
||||
is_init = true;
|
||||
}
|
||||
|
||||
float PerlinNoise2D::noise(float x, float y) {
|
||||
ASSERT_MSG(is_init, "The PerlinNoise2D don't init!");
|
||||
|
||||
int ix = static_cast<int>(std::floor(x)) & 255;
|
||||
int iy = static_cast<int>(std::floor(y)) & 255;
|
||||
|
||||
x -= std::floor(x);
|
||||
y -= std::floor(y);
|
||||
|
||||
float u = fade(x);
|
||||
float v = fade(y);
|
||||
|
||||
int a = p[ix] + iy;
|
||||
int b = p[ix + 1] + iy;
|
||||
|
||||
float res =
|
||||
lerp(v, lerp(u, grad(p[a], x, y), grad(p[b], x - 1, y)),
|
||||
lerp(u, grad(p[a + 1], x, y - 1), grad(p[b + 1], x - 1, y - 1)));
|
||||
|
||||
return (res + 1.0f) / 2.0f; // 映射到 [0, 1]
|
||||
}
|
||||
|
||||
float PerlinNoise2D::fade(float t) {
|
||||
return t * t * t * (t * (t * 6 - 15) + 10);
|
||||
}
|
||||
|
||||
float PerlinNoise2D::lerp(float t, float a, float b) { return a + t * (b - a); }
|
||||
|
||||
float PerlinNoise2D::grad(int hash, float x, float y) {
|
||||
int h = hash & 3; // 使用低 2 位选择 4 个梯度方向
|
||||
float u = (h & 1) ? -x : x;
|
||||
float v = (h & 2) ? -y : y;
|
||||
return u + v;
|
||||
}
|
||||
|
||||
void PerlinNoise2D::reload(unsigned seed) {
|
||||
is_init = false;
|
||||
p.resize(256);
|
||||
std::iota(p.begin(), p.end(), 0);
|
||||
Logger::info("Reload Perlin Noise With Seed {}", seed);
|
||||
std::shuffle(p.begin(), p.end(), std::mt19937(seed));
|
||||
|
||||
p.insert(p.end(), p.begin(), p.end());
|
||||
is_init = true;
|
||||
}
|
||||
} // namespace Cubed
|
||||
Reference in New Issue
Block a user