feat: add perlin noise

This commit is contained in:
2026-04-05 18:21:43 +08:00
parent 5ce0810294
commit 23affb78b5
10 changed files with 150 additions and 15 deletions

View File

@@ -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
)

View File

@@ -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

View File

@@ -16,6 +16,9 @@ private:
std::vector<uint8_t> m_blocks;
GLuint m_vbo = 0;
std::vector<Vertex> m_vertexs_data;
float frequency = 0.01f;
float height = 80;
public:
Chunk(World& world, ChunkPos chunk_pos);

View File

@@ -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};

View File

@@ -0,0 +1,16 @@
#pragma once
#include <vector>
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<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, float z);
};

View File

@@ -3,6 +3,7 @@
#include <Cubed/map_table.hpp>
#include <Cubed/tools/cubed_assert.hpp>
#include <Cubed/tools/log.hpp>
#include <Cubed/tools/perlin_noise.hpp>
#include <exception>
@@ -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();

View File

@@ -1,6 +1,8 @@
#include <Cubed/gameplay/chunk.hpp>
#include <Cubed/gameplay/world.hpp>
#include <Cubed/tools/cubed_assert.hpp>
#include <Cubed/tools/log.hpp>
#include <Cubed/tools/perlin_noise.hpp>
Chunk::Chunk(World& world, ChunkPos chunk_pos) :
m_world(world),
m_chunk_pos(chunk_pos)
@@ -18,15 +20,19 @@ const std::vector<uint8_t>& 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<Vertex>& 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<float>(x + m_chunk_pos.x * CHUCK_SIZE);
float world_z = static_cast<float>(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;
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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<float>(pos.x * CHUCK_SIZE) + static_cast<float>(CHUCK_SIZE / 2), static_cast<float>(CHUCK_SIZE / 2), static_cast<float>(pos.z * CHUCK_SIZE) + static_cast<float>(CHUCK_SIZE / 2));
if (is_aabb_in_frustum(center, glm::vec3(static_cast<float>(CHUCK_SIZE / 2), static_cast<float>(CHUCK_SIZE / 2), static_cast<float>(CHUCK_SIZE / 2)))) {
glm::vec3 center = glm::vec3(static_cast<float>(pos.x * CHUCK_SIZE) + static_cast<float>(CHUCK_SIZE / 2), static_cast<float>(WORLD_SIZE_Y/ 2), static_cast<float>(pos.z * CHUCK_SIZE) + static_cast<float>(CHUCK_SIZE / 2));
if (is_aabb_in_frustum(center, glm::vec3(static_cast<float>(CHUCK_SIZE / 2), static_cast<float>(WORLD_SIZE_Y / 2), static_cast<float>(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 ;
}

View File

@@ -0,0 +1,71 @@
#include <Cubed/tools/perlin_noise.hpp>
#include <Cubed/config.hpp>
#include <Cubed/tools/cubed_assert.hpp>
#include <algorithm>
#include <numeric>
#include <random>
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<int>(std::floor(x)) & 255;
int iy = static_cast<int>(std::floor(y)) & 255;
int iz = static_cast<int>(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);
}