From 23affb78b5a111d87bf1b29e3dd46721e7b86fd9 Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Sun, 5 Apr 2026 18:21:43 +0800 Subject: [PATCH] feat: add perlin noise --- CMakeLists.txt | 1 + include/Cubed/config.hpp | 6 ++- include/Cubed/gameplay/chunk.hpp | 3 ++ include/Cubed/gameplay/player.hpp | 5 +- include/Cubed/tools/perlin_noise.hpp | 16 +++++++ src/app.cpp | 4 +- src/gameplay/chunk.cpp | 34 +++++++++++-- src/gameplay/player.cpp | 16 ++++++- src/gameplay/world.cpp | 9 ++-- src/tools/perlin_noise.cpp | 71 ++++++++++++++++++++++++++++ 10 files changed, 150 insertions(+), 15 deletions(-) create mode 100644 include/Cubed/tools/perlin_noise.hpp create mode 100644 src/tools/perlin_noise.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ab30e51..c7787a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,6 +93,7 @@ add_executable(${PROJECT_NAME} src/tools/shader_tools.cpp src/tools/font.cpp src/tools/log.cpp + src/tools/perlin_noise.cpp src/window.cpp ) diff --git a/include/Cubed/config.hpp b/include/Cubed/config.hpp index 825ea8a..66620a3 100644 --- a/include/Cubed/config.hpp +++ b/include/Cubed/config.hpp @@ -1,16 +1,18 @@ #pragma once constexpr int WORLD_SIZE_X = 32; constexpr int WORLD_SIZE_Z = 32; -constexpr int WORLD_SIZE_Y = 16; +constexpr int WORLD_SIZE_Y = 256; constexpr int MAX_BLOCK_NUM = 2; constexpr int MAX_UI_NUM = 1; constexpr int CHUCK_SIZE = 16; -constexpr int DISTANCE = 8; +constexpr int DISTANCE = 16; constexpr int MAX_BLOCK_STATUS = 1; constexpr int MAX_CHARACTER = 128; constexpr float FOV = 70.0f; +constexpr int SEED = 999; + constexpr float VERTICES_POS[6][6][3] = { // ===== front (z = +1) ===== 0.0f, 0.0f, 1.0f, // bottom left diff --git a/include/Cubed/gameplay/chunk.hpp b/include/Cubed/gameplay/chunk.hpp index e9dea58..a9e1218 100644 --- a/include/Cubed/gameplay/chunk.hpp +++ b/include/Cubed/gameplay/chunk.hpp @@ -16,6 +16,9 @@ private: std::vector m_blocks; GLuint m_vbo = 0; std::vector m_vertexs_data; + + float frequency = 0.01f; + float height = 80; public: Chunk(World& world, ChunkPos chunk_pos); diff --git a/include/Cubed/gameplay/player.hpp b/include/Cubed/gameplay/player.hpp index 04b5089..7f8ef9b 100644 --- a/include/Cubed/gameplay/player.hpp +++ b/include/Cubed/gameplay/player.hpp @@ -21,7 +21,8 @@ private: float m_sensitivity = 0.15f; - float max_speed = 4.5f; + //float max_speed = 4.5f; + float max_speed = 7.5f; float y_speed = 0.0f; bool can_up = true; float speed = 0; @@ -29,7 +30,7 @@ private: glm::vec3 direction = glm::vec3(0.0f, 0.0f, 0.0f); glm::vec3 move_distance {0.0f, 0.0f, 0.0f}; // player is tow block tall, the pos is the lower pos - glm::vec3 m_player_pos {0.0f, 15.0f, 0.0f}; + glm::vec3 m_player_pos {0.0f, 120.0f, 0.0f}; glm::vec3 m_front {0, 0, -1}; glm::vec3 m_right {0, 0, 0}; glm::vec3 m_size {0.6f, 1.8f, 0.6f}; diff --git a/include/Cubed/tools/perlin_noise.hpp b/include/Cubed/tools/perlin_noise.hpp new file mode 100644 index 0000000..578d9f3 --- /dev/null +++ b/include/Cubed/tools/perlin_noise.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +class PerlinNoise { +public: + static void init(); + static float noise(float x, float y, float z); +private: + static inline bool is_init = false; + static inline std::vector p; + + static float fade(float t); + static float lerp(float t, float a, float b); + static float grad(int hash, float x, float y, float z); +}; \ No newline at end of file diff --git a/src/app.cpp b/src/app.cpp index 5d52a22..900f5bd 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -30,7 +31,8 @@ void App::init() { glfwSetWindowSizeCallback(m_window.get_glfw_window(), window_reshape_callback); glfwSetKeyCallback(m_window.get_glfw_window(), key_callback); - + PerlinNoise::init(); + m_renderer.init(); Logger::info("Renderer Init Success"); m_window.update_viewport(); diff --git a/src/gameplay/chunk.cpp b/src/gameplay/chunk.cpp index 3683031..ee21c73 100644 --- a/src/gameplay/chunk.cpp +++ b/src/gameplay/chunk.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include Chunk::Chunk(World& world, ChunkPos chunk_pos) : m_world(world), m_chunk_pos(chunk_pos) @@ -18,15 +20,19 @@ const std::vector& Chunk::get_chunk_blocks() const{ int Chunk::get_index(int x, int y, int z) { - return x * CHUCK_SIZE * CHUCK_SIZE + y * CHUCK_SIZE + z; + 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) { + Logger::error("block pos x {} y {} z {} range error", x, y, z); + CUBED_ASSERT(0); + } + return (x * WORLD_SIZE_Y + y) * CHUCK_SIZE + z; } void Chunk::gen_vertex_data() { m_vertexs_data.clear(); glDeleteBuffers(1, &m_vbo); for (int x = 0; x < CHUCK_SIZE; x++) { - for (int z = 0; z < CHUCK_SIZE; z++) { - for (int y = 0; y < CHUCK_SIZE; y++) { + for (int y = 0; y < WORLD_SIZE_Y; y++) { + for (int z = 0; z < CHUCK_SIZE; z++) { int world_x = x + m_chunk_pos.x * CHUCK_SIZE; int world_z = z + m_chunk_pos.z * CHUCK_SIZE; int world_y = y; @@ -73,7 +79,7 @@ const std::vector& Chunk::get_vertex_data() const{ } void Chunk::init_chunk() { - m_blocks.assign(CHUCK_SIZE * CHUCK_SIZE * CHUCK_SIZE, 0); + 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++) { @@ -81,6 +87,26 @@ void Chunk::init_chunk() { } } } + + for (int x = 0; x < CHUCK_SIZE; x++) { + for (int z = 0; z < CHUCK_SIZE; z++) { + + float world_x = static_cast(x + m_chunk_pos.x * CHUCK_SIZE); + float world_z = static_cast(z + m_chunk_pos.z * CHUCK_SIZE); + + float noise = + 0.5f * PerlinNoise::noise(world_x * 0.01f, world_z * 0.01f, 0.5f) + + 0.25f * PerlinNoise::noise(world_x * 0.02f, world_z * 0.02f, 0.5f) + + 0.125f * PerlinNoise::noise(world_x * 0.04f, world_z * 0.04f, 0.5f); + int y_max = height * noise; + + for (int y = 5; y < y_max; y++) { + m_blocks[get_index(x, y, z)] = 1; + } + + } + } + } diff --git a/src/gameplay/player.cpp b/src/gameplay/player.cpp index 5dd2d65..00ac82e 100644 --- a/src/gameplay/player.cpp +++ b/src/gameplay/player.cpp @@ -292,6 +292,7 @@ void Player::update_move(float delta_time) { move_distance = {direction.x * speed * delta_time, 0.0f, direction.z * speed * delta_time}; + /* if (m_move_state.up && can_up) { y_speed = 7.5; can_up = false; @@ -299,6 +300,19 @@ void Player::update_move(float delta_time) { } y_speed += -G * delta_time; + */ + if (m_move_state.up) { + y_speed = 7.5f; + } + + if (m_move_state.down) { + y_speed = -7.5f; + } + + if (!m_move_state.down && !m_move_state.up) { + y_speed = 0.0f; + } + move_distance.y = y_speed * delta_time; // y update_y_move(); @@ -308,7 +322,7 @@ void Player::update_move(float delta_time) { update_z_move(); if (m_player_pos.y < -15.0f) { - m_player_pos = glm::vec3(0.0f, 20.0f, 0.0f); + m_player_pos = glm::vec3(0.0f, 100.0f, 0.0f); } } diff --git a/src/gameplay/world.cpp b/src/gameplay/world.cpp index 5d00c87..94d2c24 100644 --- a/src/gameplay/world.cpp +++ b/src/gameplay/world.cpp @@ -102,7 +102,6 @@ void World::init_world() { m_chunks.emplace(pos, Chunk(*this, pos)); } } - Logger::info("Chunk Init Finish"); for (auto& chunk_map : m_chunks) { auto& [chunk_pos, chunk] = chunk_map; @@ -126,8 +125,8 @@ void World::render(const glm::mat4& mvp_matrix) { Math::extract_frustum_planes(mvp_matrix, m_planes); for (const auto& chunk_map : m_chunks) { const auto& [pos, chunk] = chunk_map; - glm::vec3 center = glm::vec3(static_cast(pos.x * CHUCK_SIZE) + static_cast(CHUCK_SIZE / 2), static_cast(CHUCK_SIZE / 2), static_cast(pos.z * CHUCK_SIZE) + static_cast(CHUCK_SIZE / 2)); - if (is_aabb_in_frustum(center, glm::vec3(static_cast(CHUCK_SIZE / 2), static_cast(CHUCK_SIZE / 2), static_cast(CHUCK_SIZE / 2)))) { + glm::vec3 center = glm::vec3(static_cast(pos.x * CHUCK_SIZE) + static_cast(CHUCK_SIZE / 2), static_cast(WORLD_SIZE_Y/ 2), static_cast(pos.z * CHUCK_SIZE) + static_cast(CHUCK_SIZE / 2)); + if (is_aabb_in_frustum(center, glm::vec3(static_cast(CHUCK_SIZE / 2), static_cast(WORLD_SIZE_Y / 2), static_cast(CHUCK_SIZE / 2)))) { glBindBuffer(GL_ARRAY_BUFFER, chunk.get_vbo()); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, s)); @@ -190,7 +189,7 @@ bool World::is_block(const glm::ivec3& block_pos) const{ y = world_y; x = world_x - chunk_x * CHUCK_SIZE; z = world_z - chunk_z * CHUCK_SIZE; - if (x < 0 || y < 0 || z < 0 || x >= CHUCK_SIZE || y >= CHUCK_SIZE || z >= CHUCK_SIZE) { + if (x < 0 || y < 0 || z < 0 || x >= CHUCK_SIZE || y >= WORLD_SIZE_Y || z >= CHUCK_SIZE) { return false; } auto id = chunk_blocks[Chunk::get_index(x, y, z)]; @@ -232,7 +231,7 @@ void World::set_block(const glm::ivec3& block_pos, unsigned id) { y = world_y; x = world_x - chunk_x * CHUCK_SIZE; z = world_z - chunk_z * CHUCK_SIZE; - if (x < 0 || y < 0 || z < 0 || x >= CHUCK_SIZE || y >= CHUCK_SIZE || z >= CHUCK_SIZE) { + if (x < 0 || y < 0 || z < 0 || x >= CHUCK_SIZE || y >= WORLD_SIZE_Y || z >= CHUCK_SIZE) { return ; } diff --git a/src/tools/perlin_noise.cpp b/src/tools/perlin_noise.cpp new file mode 100644 index 0000000..012de5a --- /dev/null +++ b/src/tools/perlin_noise.cpp @@ -0,0 +1,71 @@ +#include + +#include +#include + +#include +#include +#include + +void PerlinNoise::init() { + p.resize(256); + std::iota(p.begin(), p.end(), 0); + + std::mt19937 engine(SEED); + std::shuffle(p.begin(), p.end(), engine); + + p.insert(p.end(), p.begin(), p.end()); + is_init = true; +} + +float PerlinNoise::noise(float x, float y, float z) { + CUBED_ASSERT_MSG(is_init, "The PerlinNoise don't init!"); + int ix = static_cast(std::floor(x)) & 255; + int iy = static_cast(std::floor(y)) & 255; + int iz = static_cast(std::floor(z)) & 255; + + x -= std::floor(x); + y -= std::floor(y); + z -= std::floor(z); + + double u = fade(x); + double v = fade(y); + double w = fade(z); + + int a = p[ix] + iy; + int aa = p[a] + iz; + int ab = p[a + 1] + iz; + int b = p[ix + 1] + iy; + int ba = p[b] + iz; + int bb = p[b + 1] + iz; + + float res = lerp (w, + lerp (v, + lerp(u, grad(p[aa], x, y, z), grad(p[ba], x - 1, y, z)), + lerp(u, grad(p[ab], x, y - 1, z), grad(p[bb], x - 1, y - 1, z)) + ), + lerp(v, + lerp(u, grad(p[aa + 1], x, y, z - 1), grad(p[ba + 1], x - 1, y, z - 1)), + lerp(u, grad(p[ab + 1], x, y - 1, z - 1), grad(p[bb + 1 ], x - 1, y - 1, z - 1)) + ) + + ); + return (res + 1.0f) / 2.0f; +} + +float PerlinNoise::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 PerlinNoise::grad(int hash, float x, float y, float z) { + int h = hash & 15; + + float u = h < 8 ? x : y; + float v = h < 4 ? y : h == 12 || h == 14 ? x : z; + + return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); +} \ No newline at end of file