trying to restructure how chunks hold voxels
This commit is contained in:
parent
fc4960f25d
commit
4925849747
@ -115,7 +115,7 @@ class Camera
|
|||||||
for (int y = min.y; y < max.y && !collided; y++) {
|
for (int y = min.y; y < max.y && !collided; y++) {
|
||||||
for (int z = min.z; z < max.z && !collided; z++) {
|
for (int z = min.z; z < max.z && !collided; z++) {
|
||||||
glm::ivec3 calculated_position = glm::ivec3(x, y, z);
|
glm::ivec3 calculated_position = glm::ivec3(x, y, z);
|
||||||
if (world->get_voxel(calculated_position).has_value()) {
|
if (world->get_voxel(calculated_position) != VoxelKind::Air) {
|
||||||
collided = true;
|
collided = true;
|
||||||
// std::cout << "Collided!!" << std::endl;
|
// std::cout << "Collided!!" << std::endl;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,13 +49,13 @@ void addFace(glm::ivec3 pos, const float *faceVertices, float voxelKind, std::ve
|
|||||||
float world_x = v[0] + pos.x;
|
float world_x = v[0] + pos.x;
|
||||||
float world_y = v[1] + pos.y;
|
float world_y = v[1] + pos.y;
|
||||||
float world_z = v[2] + pos.z;
|
float world_z = v[2] + pos.z;
|
||||||
|
|
||||||
// Debug: Print first vertex of first face
|
// Debug: Print first vertex of first face
|
||||||
if (vbo.empty() && i == 0) {
|
if (vbo.empty() && i == 0) {
|
||||||
std::cout << "[MESH] First vertex - Local pos: (" << pos.x << ", " << pos.y << ", " << pos.z << ")" << std::endl;
|
std::cout << "[MESH] First vertex - Local pos: (" << pos.x << ", " << pos.y << ", " << pos.z << ")" << std::endl;
|
||||||
std::cout << "[MESH] First vertex - World: (" << world_x << ", " << world_y << ", " << world_z << ")" << std::endl;
|
std::cout << "[MESH] First vertex - World: (" << world_x << ", " << world_y << ", " << world_z << ")" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
vbo.push_back(world_x);
|
vbo.push_back(world_x);
|
||||||
vbo.push_back(world_y);
|
vbo.push_back(world_y);
|
||||||
vbo.push_back(world_z);
|
vbo.push_back(world_z);
|
||||||
@ -73,16 +73,12 @@ void addFace(glm::ivec3 pos, const float *faceVertices, float voxelKind, std::ve
|
|||||||
}
|
}
|
||||||
|
|
||||||
Chunk::Chunk() {
|
Chunk::Chunk() {
|
||||||
// mesh is initially null (nullptr)
|
this->data.fill(VoxelKind::Air);
|
||||||
}
|
|
||||||
|
|
||||||
Chunk::Chunk(std::unordered_map<glm::ivec3, VoxelKind> 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 && !this->isEmpty()) {
|
||||||
generateMesh();
|
generateMesh();
|
||||||
}
|
}
|
||||||
return mesh.get();
|
return mesh.get();
|
||||||
@ -103,14 +99,35 @@ void Chunk::generateMesh() {
|
|||||||
std::pair(glm::ivec3(0, 0, -1), backFace) // back
|
std::pair(glm::ivec3(0, 0, -1), backFace) // back
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const std::pair<const glm::ivec3, VoxelKind>& pair : voxels) {
|
for (int i = 0; i < TOTAL; ++i) {
|
||||||
const glm::ivec3& pos = pair.first;
|
VoxelKind kind = this->data[i];
|
||||||
const VoxelKind& kind = pair.second;
|
if (kind == VoxelKind::Air) continue;
|
||||||
|
|
||||||
for (const std::pair<glm::ivec3, const float*>& neighborPair : neighbors) {
|
int x = i % SIZE;
|
||||||
|
int y = (i / SIZE) % SIZE;
|
||||||
|
int z = i / (SIZE * SIZE);
|
||||||
|
|
||||||
|
glm::ivec3 pos(x, y, z);
|
||||||
|
|
||||||
|
for (const auto& neighborPair : neighbors) {
|
||||||
glm::ivec3 dir = neighborPair.first;
|
glm::ivec3 dir = neighborPair.first;
|
||||||
const float* face = neighborPair.second;
|
const float* face = neighborPair.second;
|
||||||
if (voxels.count(pos + dir) == 0) {
|
int nx = x + dir.x;
|
||||||
|
int ny = y + dir.y;
|
||||||
|
int nz = z + dir.z;
|
||||||
|
|
||||||
|
bool neighbour_is_solid = false;
|
||||||
|
// in-bounds neighbor -> check data
|
||||||
|
if (nx >= 0 && nx < SIZE && ny >= 0 && ny < SIZE && nz >= 0 && nz < SIZE) {
|
||||||
|
std::cout << "Accessing " << nx << ", " << ny << ", " << nz << std::endl;
|
||||||
|
neighbour_is_solid = (data[index(nx, ny, nz)] != VoxelKind::Air);
|
||||||
|
} else {
|
||||||
|
// neighbour out of this chunk: treat as air (exposed face)
|
||||||
|
// or call into World to query adjacent chunk here
|
||||||
|
neighbour_is_solid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!neighbour_is_solid) {
|
||||||
addFace(pos, face, static_cast<float>(kind), vboData, eboData);
|
addFace(pos, face, static_cast<float>(kind), vboData, eboData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,10 +144,5 @@ void Chunk::generateMesh() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Chunk::regenerateMesh() {
|
void Chunk::regenerateMesh() {
|
||||||
std::cout << "[REGENERATE] Regenerating mesh with " << voxels.size() << " voxels" << std::endl;
|
|
||||||
if (!voxels.empty()) {
|
|
||||||
auto first = voxels.begin();
|
|
||||||
std::cout << "[REGENERATE] First voxel at local: (" << first->first.x << ", " << first->first.y << ", " << first->first.z << ")" << std::endl;
|
|
||||||
}
|
|
||||||
this->generateMesh();
|
this->generateMesh();
|
||||||
}
|
}
|
||||||
|
|||||||
45
src/Chunk.h
45
src/Chunk.h
@ -1,14 +1,19 @@
|
|||||||
#ifndef CHUNK_H
|
#ifndef CHUNK_H
|
||||||
#define CHUNK_H
|
#define CHUNK_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <array>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include "Mesh.h"
|
#include "Mesh.h"
|
||||||
|
|
||||||
enum VoxelKind {
|
enum class VoxelKind : uint8_t {
|
||||||
|
Air,
|
||||||
Dirt,
|
Dirt,
|
||||||
Stone
|
Stone
|
||||||
};
|
};
|
||||||
@ -16,6 +21,7 @@ enum VoxelKind {
|
|||||||
const int CHUNK_SIZE = 32;
|
const int CHUNK_SIZE = 32;
|
||||||
|
|
||||||
// Hash function for glm::ivec3 to use with unordered_set
|
// Hash function for glm::ivec3 to use with unordered_set
|
||||||
|
// Still used in World.h
|
||||||
namespace std {
|
namespace std {
|
||||||
template <>
|
template <>
|
||||||
struct hash<glm::ivec3> {
|
struct hash<glm::ivec3> {
|
||||||
@ -33,18 +39,49 @@ namespace std {
|
|||||||
|
|
||||||
class Chunk {
|
class Chunk {
|
||||||
public:
|
public:
|
||||||
std::unordered_map<glm::ivec3, VoxelKind> voxels;
|
|
||||||
|
|
||||||
Chunk();
|
Chunk();
|
||||||
Chunk(std::unordered_map<glm::ivec3, VoxelKind> voxels);
|
|
||||||
|
|
||||||
Mesh* getMesh(); // Returns pointer, can be null if not generated yet
|
Mesh* getMesh(); // Returns pointer, can be null if not generated yet
|
||||||
|
|
||||||
void generateMesh();
|
void generateMesh();
|
||||||
void regenerateMesh();
|
void regenerateMesh();
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
inline VoxelKind get(int x, int y, int z) const {
|
||||||
|
return data[index(x, y, z)];
|
||||||
|
}
|
||||||
|
inline VoxelKind get(glm::ivec3 pos) const {
|
||||||
|
std::cout << "Getting Pos (" << pos.x << ", " << pos.y << ", " << pos.z << ")" << std::endl;
|
||||||
|
return data[index(pos.x, pos.y, pos.z)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mutators
|
||||||
|
inline void set(int x, int y, int z, VoxelKind v) {
|
||||||
|
data[index(x, y, z)] = v;
|
||||||
|
}
|
||||||
|
inline void set(glm::ivec3 pos, VoxelKind v) {
|
||||||
|
// std::cout << "Setting Pos (" << pos.x << ", " << pos.y << ", " << pos.z << ")" << std::endl;
|
||||||
|
data[index(pos.x, pos.y, pos.z)] = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other
|
||||||
|
inline bool isEmpty() const {
|
||||||
|
return std::all_of(data.begin(), data.end(), [](VoxelKind k){
|
||||||
|
return k == VoxelKind::Air;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static constexpr int SIZE = CHUNK_SIZE;
|
||||||
|
static constexpr int TOTAL = SIZE * SIZE * SIZE;
|
||||||
|
std::array<VoxelKind, TOTAL + 1> data;
|
||||||
|
|
||||||
std::unique_ptr<Mesh> mesh; // Nullable mesh
|
std::unique_ptr<Mesh> mesh; // Nullable mesh
|
||||||
|
|
||||||
|
static inline constexpr int index(int x, int y, int z) noexcept {
|
||||||
|
return x + (y * SIZE) + (z * SIZE * SIZE);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif CHUNK_H
|
#endif // CHUNK_H
|
||||||
|
|||||||
@ -22,29 +22,26 @@ glm::ivec3 floor_divide(glm::ivec3 value, int divisor) {
|
|||||||
|
|
||||||
World::World() {}
|
World::World() {}
|
||||||
|
|
||||||
void World::set_voxel(glm::ivec3 position, std::optional<VoxelKind> kind) {
|
void World::set_voxel(glm::ivec3 position, VoxelKind kind) {
|
||||||
glm::ivec3 chunk_position = floor_divide(position, CHUNK_SIZE);
|
glm::ivec3 chunk_position = floor_divide(position, CHUNK_SIZE);
|
||||||
glm::ivec3 local_position = positive_modulo(position, CHUNK_SIZE);
|
glm::ivec3 local_position = positive_modulo(position, CHUNK_SIZE);
|
||||||
|
|
||||||
std::cout << "[SET_VOXEL] World pos: (" << position.x << ", " << position.y << ", " << position.z << ")" << std::endl;
|
// std::cout << "[SET_VOXEL] World pos: (" << position.x << ", " << position.y << ", " << position.z << ")" << std::endl;
|
||||||
std::cout << "[SET_VOXEL] Chunk pos: (" << chunk_position.x << ", " << chunk_position.y << ", " << chunk_position.z << ")" << std::endl;
|
// std::cout << "[SET_VOXEL] Chunk pos: (" << chunk_position.x << ", " << chunk_position.y << ", " << chunk_position.z << ")" << std::endl;
|
||||||
std::cout << "[SET_VOXEL] Local pos: (" << local_position.x << ", " << local_position.y << ", " << local_position.z << ")" << std::endl;
|
// std::cout << "[SET_VOXEL] Local pos: (" << local_position.x << ", " << local_position.y << ", " << local_position.z << ")" << std::endl;
|
||||||
|
|
||||||
Chunk * chunk = get_or_create_chunk(chunk_position);
|
Chunk * chunk = get_or_create_chunk(chunk_position);
|
||||||
if (!kind.has_value()) {
|
chunk->set(local_position, kind);
|
||||||
chunk->voxels.erase(chunk->voxels.find(local_position));
|
|
||||||
} else {
|
|
||||||
chunk->voxels[local_position] = kind.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk->regenerateMesh();
|
chunk->regenerateMesh();
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|
||||||
|
|
||||||
// Fill in new chunk with a flat plane of voxels at y=0
|
// Fill in new chunk with a flat plane of voxels at y=0
|
||||||
std::unordered_map<glm::ivec3, VoxelKind> voxels;
|
auto [it, inserted] = this->chunks.try_emplace(chunk_position);
|
||||||
|
Chunk& chunk = it->second;
|
||||||
|
if (inserted) {
|
||||||
if (chunk_position.y == 0) {
|
if (chunk_position.y == 0) {
|
||||||
for (int z = 0; z < CHUNK_SIZE; z++) {
|
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||||
for (int y = 0; y < CHUNK_SIZE; y++) {
|
for (int y = 0; y < CHUNK_SIZE; y++) {
|
||||||
@ -52,19 +49,23 @@ Chunk* World::get_or_create_chunk(glm::ivec3 chunk_position) {
|
|||||||
glm::ivec3 offset = glm::ivec3(x, y, z);
|
glm::ivec3 offset = glm::ivec3(x, y, z);
|
||||||
glm::ivec3 world_voxel_position = chunk_position * CHUNK_SIZE + offset;
|
glm::ivec3 world_voxel_position = chunk_position * CHUNK_SIZE + offset;
|
||||||
|
|
||||||
|
VoxelKind kind;
|
||||||
if (world_voxel_position.y == 0) {
|
if (world_voxel_position.y == 0) {
|
||||||
voxels[offset] = VoxelKind::Dirt;
|
kind = VoxelKind::Dirt;
|
||||||
} else if (world_voxel_position.y < 0) {
|
} else if (world_voxel_position.y < 0) {
|
||||||
voxels[offset] = VoxelKind::Stone;
|
kind = VoxelKind::Stone;
|
||||||
|
} else {
|
||||||
|
kind = VoxelKind::Air;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chunk.set(offset, kind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->chunks[chunk_position] = Chunk(voxels);
|
|
||||||
}
|
}
|
||||||
return &this->chunks[chunk_position];
|
|
||||||
|
return &chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::pair<glm::ivec3, glm::ivec3>> World::raycast_voxel(glm::vec3 start, glm::vec3 direction, float max_dist) {
|
std::optional<std::pair<glm::ivec3, glm::ivec3>> World::raycast_voxel(glm::vec3 start, glm::vec3 direction, float max_dist) {
|
||||||
@ -133,7 +134,7 @@ std::optional<std::pair<glm::ivec3, glm::ivec3>> World::raycast_voxel(glm::vec3
|
|||||||
|
|
||||||
// std::cout << "[RAYCAST] Iteration " << iterations << " at voxel (" << pos.x << ", " << pos.y << ", " << pos.z << ")" << std::endl;
|
// std::cout << "[RAYCAST] Iteration " << iterations << " at voxel (" << pos.x << ", " << pos.y << ", " << pos.z << ")" << std::endl;
|
||||||
|
|
||||||
if (this->get_voxel(pos).has_value()) {
|
if (this->get_voxel(pos) != VoxelKind::Air) {
|
||||||
// std::cout << "[RAYCAST] Hit voxel at (" << pos.x << ", " << pos.y << ", " << pos.z << ") after " << iterations << " iterations" << std::endl;
|
// std::cout << "[RAYCAST] Hit voxel at (" << pos.x << ", " << pos.y << ", " << pos.z << ") after " << iterations << " iterations" << std::endl;
|
||||||
// std::cout << "[RAYCAST] Returning normal: (" << -last_move.x << ", " << -last_move.y << ", " << -last_move.z << ")" << std::endl;
|
// std::cout << "[RAYCAST] Returning normal: (" << -last_move.x << ", " << -last_move.y << ", " << -last_move.z << ")" << std::endl;
|
||||||
return std::make_pair(pos, -last_move);
|
return std::make_pair(pos, -last_move);
|
||||||
@ -162,14 +163,11 @@ std::optional<std::pair<glm::ivec3, glm::ivec3>> World::raycast_voxel(glm::vec3
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<VoxelKind> World::get_voxel(glm::ivec3 position) {
|
VoxelKind World::get_voxel(glm::ivec3 position) {
|
||||||
glm::ivec3 chunk_position = floor_divide(position, CHUNK_SIZE);
|
glm::ivec3 chunk_position = floor_divide(position, CHUNK_SIZE);
|
||||||
glm::ivec3 local_position = positive_modulo(position, CHUNK_SIZE);
|
glm::ivec3 local_position = positive_modulo(position, CHUNK_SIZE);
|
||||||
|
|
||||||
Chunk* chunk = this->get_or_create_chunk(chunk_position);
|
Chunk* chunk = this->get_or_create_chunk(chunk_position);
|
||||||
auto it = chunk->voxels.find(local_position);
|
|
||||||
if (it != chunk->voxels.end()) {
|
return chunk->get(position);
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,11 +15,11 @@ class World
|
|||||||
|
|
||||||
World();
|
World();
|
||||||
|
|
||||||
void set_voxel(glm::ivec3 position, std::optional<VoxelKind> kind);
|
void set_voxel(glm::ivec3 position, VoxelKind kind);
|
||||||
|
|
||||||
std::optional<std::pair<glm::ivec3, glm::ivec3>> raycast_voxel(glm::vec3 start, glm::vec3 direction, float max_dist);
|
std::optional<std::pair<glm::ivec3, glm::ivec3>> raycast_voxel(glm::vec3 start, glm::vec3 direction, float max_dist);
|
||||||
|
|
||||||
std::optional<VoxelKind> get_voxel(glm::ivec3 position);
|
VoxelKind get_voxel(glm::ivec3 position);
|
||||||
|
|
||||||
Chunk* get_or_create_chunk(glm::ivec3 chunk_position);
|
Chunk* get_or_create_chunk(glm::ivec3 chunk_position);
|
||||||
};
|
};
|
||||||
|
|||||||
14
src/main.cpp
14
src/main.cpp
@ -248,7 +248,7 @@ void processInput(GLFWwindow *window)
|
|||||||
auto [target_block, normal] = raycast_result.value();
|
auto [target_block, normal] = raycast_result.value();
|
||||||
std::cout << "Hit block at: (" << target_block.x << ", " << target_block.y << ", " << target_block.z << ")" << std::endl;
|
std::cout << "Hit block at: (" << target_block.x << ", " << target_block.y << ", " << target_block.z << ")" << std::endl;
|
||||||
std::cout << "Removing block at: (" << target_block.x << ", " << target_block.y << ", " << target_block.z << ")" << std::endl;
|
std::cout << "Removing block at: (" << target_block.x << ", " << target_block.y << ", " << target_block.z << ")" << std::endl;
|
||||||
world.set_voxel(target_block, std::nullopt);
|
world.set_voxel(target_block, VoxelKind::Air);
|
||||||
} else {
|
} else {
|
||||||
std::cout << "No block hit within range" << std::endl;
|
std::cout << "No block hit within range" << std::endl;
|
||||||
}
|
}
|
||||||
@ -437,18 +437,6 @@ int main() {
|
|||||||
Chunk* chunk = world.get_or_create_chunk(chunk_pos);
|
Chunk* chunk = world.get_or_create_chunk(chunk_pos);
|
||||||
|
|
||||||
Mesh* chunk_mesh = chunk->getMesh();
|
Mesh* chunk_mesh = chunk->getMesh();
|
||||||
if (chunk_mesh) {
|
|
||||||
// Debug: Log when rendering chunks with your placed block
|
|
||||||
static bool logged_placed_block = false;
|
|
||||||
if (!logged_placed_block && chunk->voxels.count(glm::ivec3(0, 1, 31)) > 0) {
|
|
||||||
std::cout << "\n[RENDER] ===== FOUND PLACED BLOCK =====" << std::endl;
|
|
||||||
std::cout << "[RENDER] Drawing chunk at pos (" << chunk_pos.x << ", " << chunk_pos.y << ", " << chunk_pos.z << ")" << std::endl;
|
|
||||||
std::cout << "[RENDER] Translation: (" << (chunk_pos.x * CHUNK_SIZE) << ", " << (chunk_pos.y * CHUNK_SIZE) << ", " << (chunk_pos.z * CHUNK_SIZE) << ")" << std::endl;
|
|
||||||
std::cout << "[RENDER] Final world position should be: (" << (chunk_pos.x * CHUNK_SIZE + 0) << ", " << (chunk_pos.y * CHUNK_SIZE + 1) << ", " << (chunk_pos.z * CHUNK_SIZE + 31) << ")" << std::endl;
|
|
||||||
logged_placed_block = true;
|
|
||||||
}
|
|
||||||
chunk_mesh->draw();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user