add infinite chunk generation
This commit is contained in:
parent
3ba2d75cff
commit
1ee72dae9a
BIN
.attachments/chunk-generation.png
Normal file
BIN
.attachments/chunk-generation.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
@ -18,3 +18,8 @@ Instead of making the _entire_ world a single mesh, now the world is made up of
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## 0.4.0 : Chunk Generation - 11/12/25
|
||||||
|
|
||||||
|
Chunks now generate around the player in a square based on a render distance. This allows the flat plane to be infinite!
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
@ -73,9 +73,9 @@ class Camera
|
|||||||
|
|
||||||
void move(float time) // time passed in seconds since last move
|
void move(float time) // time passed in seconds since last move
|
||||||
{
|
{
|
||||||
bool in_air = this->position.y > 0;
|
bool in_air = this->position.y > 1;
|
||||||
|
|
||||||
if (this->position.y > 0)
|
if (this->position.y > 1)
|
||||||
this->vertical_velocity.y -= (GRAVITY * time); // no way! physics reference?
|
this->vertical_velocity.y -= (GRAVITY * time); // no way! physics reference?
|
||||||
|
|
||||||
glm::vec3 velocity = this->forward_velocity + this->horizontal_velocity + this->vertical_velocity;
|
glm::vec3 velocity = this->forward_velocity + this->horizontal_velocity + this->vertical_velocity;
|
||||||
@ -84,7 +84,7 @@ class Camera
|
|||||||
this->position += movement;
|
this->position += movement;
|
||||||
|
|
||||||
// Don't want to clip into the ground right
|
// Don't want to clip into the ground right
|
||||||
if (this->position.y <= 0 && in_air)
|
if (this->position.y <= 1 && in_air)
|
||||||
{
|
{
|
||||||
this->position.y = 0.0f;
|
this->position.y = 0.0f;
|
||||||
this->vertical_velocity.y = 0.0f;
|
this->vertical_velocity.y = 0.0f;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "Chunk.h"
|
#include "Chunk.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
const int VERTEX_SIZE = 6;
|
const int VERTEX_SIZE = 6;
|
||||||
|
|
||||||
@ -64,6 +65,10 @@ Chunk::Chunk() {
|
|||||||
// mesh is initially null (nullptr)
|
// mesh is initially null (nullptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Chunk::Chunk(std::unordered_set<glm::ivec3> voxels) {
|
||||||
|
this->voxels = voxels;
|
||||||
|
}
|
||||||
|
|
||||||
Mesh* Chunk::getMesh() {
|
Mesh* Chunk::getMesh() {
|
||||||
// Generate mesh on first access if not already generated
|
// Generate mesh on first access if not already generated
|
||||||
if (!mesh && !voxels.empty()) {
|
if (!mesh && !voxels.empty()) {
|
||||||
@ -76,6 +81,8 @@ void Chunk::generateMesh() {
|
|||||||
std::vector<float> vboData;
|
std::vector<float> vboData;
|
||||||
std::vector<unsigned int> eboData;
|
std::vector<unsigned int> eboData;
|
||||||
|
|
||||||
|
// std::cout << "Generating Chunk mesh..." << std::endl;
|
||||||
|
|
||||||
for (const glm::ivec3 pos : voxels) {
|
for (const glm::ivec3 pos : voxels) {
|
||||||
if (voxels.count(pos + glm::ivec3(0, 1, 0)) == 0) {
|
if (voxels.count(pos + glm::ivec3(0, 1, 0)) == 0) {
|
||||||
addFace(pos, topFace, vboData, eboData);
|
addFace(pos, topFace, vboData, eboData);
|
||||||
|
|||||||
@ -31,6 +31,7 @@ class Chunk {
|
|||||||
std::unordered_set<glm::ivec3> voxels;
|
std::unordered_set<glm::ivec3> voxels;
|
||||||
|
|
||||||
Chunk();
|
Chunk();
|
||||||
|
Chunk(std::unordered_set<glm::ivec3> voxels);
|
||||||
|
|
||||||
Mesh* getMesh(); // Returns pointer, can be null if not generated yet
|
Mesh* getMesh(); // Returns pointer, can be null if not generated yet
|
||||||
|
|
||||||
|
|||||||
@ -40,7 +40,7 @@ void Mesh::init() {
|
|||||||
void Mesh::uploadData(const std::vector<float> &vboData, const std::vector<unsigned int> &eboData) {
|
void Mesh::uploadData(const std::vector<float> &vboData, const std::vector<unsigned int> &eboData) {
|
||||||
m_indexCount = eboData.size();
|
m_indexCount = eboData.size();
|
||||||
|
|
||||||
std::cout << "Uploading mesh: " << vboData.size() << " floats, " << eboData.size() << " indices" << std::endl;
|
// std::cout << "Uploading mesh: " << vboData.size() << " floats, " << eboData.size() << " indices" << std::endl;
|
||||||
|
|
||||||
// Bind VAO first, then upload buffer data
|
// Bind VAO first, then upload buffer data
|
||||||
glBindVertexArray(m_VAO);
|
glBindVertexArray(m_VAO);
|
||||||
|
|||||||
@ -16,7 +16,18 @@ void World::flip_voxel(glm::ivec3 position) {
|
|||||||
|
|
||||||
Chunk* World::get_or_create_chunk(glm::ivec3 chunk_position) {
|
Chunk* World::get_or_create_chunk(glm::ivec3 chunk_position) {
|
||||||
if (this->chunks.count(chunk_position) == 0) {
|
if (this->chunks.count(chunk_position) == 0) {
|
||||||
this->chunks[chunk_position] = Chunk();
|
|
||||||
|
// Fill in new chunk with a flat plane of voxels at y=0
|
||||||
|
std::unordered_set<glm::ivec3> voxels;
|
||||||
|
if (chunk_position.y == 0) {
|
||||||
|
for (int z = 0; z <= 32; z++) {
|
||||||
|
for (int x = 0; x <= 32; x++) {
|
||||||
|
voxels.insert(glm::ivec3(x, 0, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->chunks[chunk_position] = Chunk(voxels);
|
||||||
}
|
}
|
||||||
return &this->chunks[chunk_position];
|
return &this->chunks[chunk_position];
|
||||||
}
|
}
|
||||||
|
|||||||
74
src/main.cpp
74
src/main.cpp
@ -28,10 +28,12 @@ const float Z_NEAR = 0.1f;
|
|||||||
bool WIREFRAME_MODE = !true;
|
bool WIREFRAME_MODE = !true;
|
||||||
const float FOV = 110.0f;
|
const float FOV = 110.0f;
|
||||||
|
|
||||||
|
const int VIEW_DISTANCE = 4; // In Chunks
|
||||||
|
|
||||||
bool W_pressed, S_pressed, A_pressed, D_pressed = false;
|
bool W_pressed, S_pressed, A_pressed, D_pressed = false;
|
||||||
|
|
||||||
glm::mat4 projection = glm::mat4(1.0f);
|
glm::mat4 projection = glm::mat4(1.0f);
|
||||||
Camera camera = Camera(CAMERA_SPEED, glm::vec3(0.0f, 0.0f, 3.0f));
|
Camera camera = Camera(CAMERA_SPEED, glm::vec3(0.0f, 1.0f, 3.0f));
|
||||||
|
|
||||||
// Callback function for when the window is resized
|
// Callback function for when the window is resized
|
||||||
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
|
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
|
||||||
@ -181,7 +183,7 @@ int main() {
|
|||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
|
||||||
// 2. --- Create a Window ---
|
// 2. --- Create a Window ---
|
||||||
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "HelloTriangle", NULL, NULL);
|
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Voxel Engine 0.4.0", NULL, NULL);
|
||||||
if (window == NULL) {
|
if (window == NULL) {
|
||||||
std::cerr << "Failed to create GLFW window" << std::endl;
|
std::cerr << "Failed to create GLFW window" << std::endl;
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
@ -205,17 +207,9 @@ int main() {
|
|||||||
|
|
||||||
// Load Cube OBJ
|
// Load Cube OBJ
|
||||||
World world;
|
World world;
|
||||||
Object3D cube = Object3D("objs/cube.obj");
|
// Object3D cube = Object3D("objs/cube.obj");
|
||||||
|
|
||||||
// Place cubes in the world
|
// std::cout << "World created with " << world.chunks.size() << " chunks" << std::endl;
|
||||||
for (int z = 0; z <= 256; z++) {
|
|
||||||
for (int x = 0; x <= 256; x++) {
|
|
||||||
world.flip_voxel(glm::ivec3(x, -1, z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
world.flip_voxel(glm::ivec3(7, 0, 13));
|
|
||||||
std::cout << "World created with " << world.chunks.size() << " chunks" << std::endl;
|
|
||||||
// Mesh generation now happens automatically when first rendering
|
// Mesh generation now happens automatically when first rendering
|
||||||
|
|
||||||
if (WIREFRAME_MODE)
|
if (WIREFRAME_MODE)
|
||||||
@ -251,31 +245,35 @@ int main() {
|
|||||||
std::cout << "\n=== RENDER DEBUG ===" << std::endl;
|
std::cout << "\n=== RENDER DEBUG ===" << std::endl;
|
||||||
std::cout << "Camera pos: (" << camera.position.x << ", " << camera.position.y << ", " << camera.position.z << ")" << std::endl;
|
std::cout << "Camera pos: (" << camera.position.x << ", " << camera.position.y << ", " << camera.position.z << ")" << std::endl;
|
||||||
std::cout << "Camera target: (" << camera.target.x << ", " << camera.target.y << ", " << camera.target.z << ")" << std::endl;
|
std::cout << "Camera target: (" << camera.target.x << ", " << camera.target.y << ", " << camera.target.z << ")" << std::endl;
|
||||||
std::cout << "Number of chunks to draw: " << world.chunks.size() << std::endl;
|
// std::cout << "Number of chunks to draw: " << world.chunks.size() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate chunks around the camera
|
||||||
|
glm::ivec3 camera_chunk = glm::ivec3(camera.position) / CHUNK_SIZE;
|
||||||
|
|
||||||
// ---- PASS 1: Draw solid grey cubes ----
|
// ---- PASS 1: Draw solid grey cubes ----
|
||||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||||
glPolygonOffset(1.0, 1.0); // Push solid faces "back"
|
glPolygonOffset(1.0, 1.0); // Push solid faces "back"
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
shader.setVec3("u_Color", glm::vec3(0.5, 0.5, 0.5));
|
shader.setVec3("u_Color", glm::vec3(0.5, 0.5, 0.5));
|
||||||
|
|
||||||
for (auto& [chunk_position, chunk] : world.chunks) {
|
for (int y = -VIEW_DISTANCE; y < VIEW_DISTANCE; y++) {
|
||||||
|
for (int z = -VIEW_DISTANCE; z < VIEW_DISTANCE; z++) {
|
||||||
|
for (int x = -VIEW_DISTANCE; x < VIEW_DISTANCE; x++) {
|
||||||
|
glm::ivec3 chunk_offset = glm::ivec3(x, y, z);
|
||||||
|
glm::ivec3 chunk_pos = camera_chunk + chunk_offset;
|
||||||
|
|
||||||
glm::ivec3 chunk_offset = chunk_position * CHUNK_SIZE;
|
glm::mat4 model = glm::mat4(1.0f);
|
||||||
glm::mat4 model = glm::mat4(1.0f);
|
model = glm::translate(model, glm::vec3(chunk_pos * CHUNK_SIZE));
|
||||||
model = glm::translate(model, glm::vec3(chunk_offset));
|
glm::mat4 mvp = projection * view * model;
|
||||||
glm::mat4 mvp = projection * view * model;
|
shader.setMat4("u_mvp", mvp);
|
||||||
shader.setMat4("u_mvp", mvp);
|
|
||||||
|
|
||||||
if (!debug_printed) {
|
Chunk* chunk = world.get_or_create_chunk(chunk_pos);
|
||||||
std::cout << "Drawing chunk at (" << chunk_position.x << ", " << chunk_position.y << ", " << chunk_position.z << ")" << std::endl;
|
|
||||||
std::cout << "Chunk offset: (" << chunk_offset.x << ", " << chunk_offset.y << ", " << chunk_offset.z << ")" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mesh* chunkMesh = chunk.getMesh();
|
Mesh* chunk_mesh = chunk->getMesh();
|
||||||
if (chunkMesh) {
|
if (chunk_mesh)
|
||||||
chunkMesh->draw();
|
chunk_mesh->draw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,17 +287,23 @@ int main() {
|
|||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Just the lines
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // Just the lines
|
||||||
shader.setVec3("u_Color", glm::vec3(1.0, 1.0, 1.0));
|
shader.setVec3("u_Color", glm::vec3(1.0, 1.0, 1.0));
|
||||||
|
|
||||||
for (auto& [chunk_position, chunk] : world.chunks) {
|
for (int y = -VIEW_DISTANCE; y < VIEW_DISTANCE; y++) {
|
||||||
|
for (int z = -VIEW_DISTANCE; z < VIEW_DISTANCE; z++) {
|
||||||
|
for (int x = -VIEW_DISTANCE; x < VIEW_DISTANCE; x++) {
|
||||||
|
glm::ivec3 chunk_offset = glm::ivec3(x, y, z);
|
||||||
|
glm::ivec3 chunk_pos = camera_chunk + chunk_offset;
|
||||||
|
|
||||||
glm::ivec3 chunk_offset = chunk_position * CHUNK_SIZE;
|
glm::mat4 model = glm::mat4(1.0f);
|
||||||
glm::mat4 model = glm::mat4(1.0f);
|
model = glm::translate(model, glm::vec3(chunk_pos * CHUNK_SIZE));
|
||||||
model = glm::translate(model, glm::vec3(chunk_offset));
|
glm::mat4 mvp = projection * view * model;
|
||||||
glm::mat4 mvp = projection * view * model;
|
shader.setMat4("u_mvp", mvp);
|
||||||
shader.setMat4("u_mvp", mvp);
|
|
||||||
|
|
||||||
Mesh* chunkMesh = chunk.getMesh();
|
Chunk* chunk = world.get_or_create_chunk(chunk_pos);
|
||||||
if (chunkMesh) {
|
|
||||||
chunkMesh->draw();
|
Mesh* chunk_mesh = chunk->getMesh();
|
||||||
|
if (chunk_mesh)
|
||||||
|
chunk_mesh->draw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user