diff options
| author | Mel <einebeere@gmail.com> | 2023-07-10 04:42:49 +0200 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2023-07-10 04:42:49 +0200 |
| commit | 354a49d852d8f9ed9b66d7780ba43ce3a9ec59d7 (patch) | |
| tree | 5f311f6aa47db9a231164a82403cc0e1e53864e8 /src/World/Generation/ChunkMeshing.cpp | |
| parent | 22aeb320b193705f493747714404c8ddc752919b (diff) | |
| download | meowcraft-354a49d852d8f9ed9b66d7780ba43ce3a9ec59d7.tar.zst meowcraft-354a49d852d8f9ed9b66d7780ba43ce3a9ec59d7.zip | |
Separate transparent water mesh (not sorted, bad)
Diffstat (limited to 'src/World/Generation/ChunkMeshing.cpp')
| -rw-r--r-- | src/World/Generation/ChunkMeshing.cpp | 286 |
1 files changed, 140 insertions, 146 deletions
diff --git a/src/World/Generation/ChunkMeshing.cpp b/src/World/Generation/ChunkMeshing.cpp index 130bbad..7158734 100644 --- a/src/World/Generation/ChunkMeshing.cpp +++ b/src/World/Generation/ChunkMeshing.cpp @@ -2,36 +2,49 @@ namespace MC::World::Generation::ChunkMeshing { -Chunk::BlockData get_block_wrapping(const Chunk& chunk, const ChunkNeighbors& neighbors, Vector<3, I32> pos) { - const Chunk* chunk_to_ask; +ChunkMesh mesh_chunk(Chunk& chunk, const ChunkNeighbors& neighbors) { + using namespace Detail; - auto overflow = [](I32& c, I32 max) -> I8 { - if (c < 0) { c += max; return -1; } - if (c >= max) { c -= max; return 1; } - return 0; + return { + create_mesh<DefaultMeshDecisions>(chunk, neighbors), + create_mesh<WaterMeshDecisions>(chunk, neighbors) }; +} - auto xo = overflow(pos.x(), Chunk::Width); - auto yo = overflow(pos.y(), Chunk::Height); - auto zo = overflow(pos.z(), Chunk::Width); - - // Blocks above and below a chunk are always Air. - if (yo != 0) return {}; +namespace Detail { - if (xo == 1 && zo == 1) { chunk_to_ask = neighbors.south_east; } - else if (xo == 1 && zo == -1) { chunk_to_ask = neighbors.north_east; } - else if (xo == -1 && zo == 1) { chunk_to_ask = neighbors.south_west; } - else if (xo == -1 && zo == -1) { chunk_to_ask = neighbors.north_west; } - else if (xo == 1) { chunk_to_ask = neighbors.east; } - else if (xo == -1) { chunk_to_ask = neighbors.west; } - else if (zo == 1) { chunk_to_ask = neighbors.south; } - else if (zo == -1) { chunk_to_ask = neighbors.north; } - else { chunk_to_ask = &chunk; } +std::array<Vector<3, F32>, 4> DefaultMeshDecisions::face_positions(BlockSide side, U32 x, U32 y, U32 z) { + // Winding order: (0, 1, 2) (2, 3, 0) + // Note: OpenGL Coordinate system has a flipped z axis. + std::array<Vector<3, F32>, 4> face{}; + switch (side) { + case BlockSide::Front: + face = {{{0, 1, 1}, {0, 0, 1}, {1, 0, 1}, {1, 1, 1}}}; + break; + case BlockSide::Back: + face = {{{0, 1, 0}, {1, 1, 0}, {1, 0, 0}, {0, 0, 0}}}; + break; + case BlockSide::Top: + face = {{{0, 1, 1}, {1, 1, 1}, {1, 1, 0}, {0, 1, 0}}}; + break; + case BlockSide::Bottom: + face = {{{0, 0, 1}, {0, 0, 0}, {1, 0, 0}, {1, 0, 1}}}; + break; + case BlockSide::Right: + face = {{{1, 1, 0}, {1, 1, 1}, {1, 0, 1}, {1, 0, 0}}}; + break; + case BlockSide::Left: + face = {{{0, 1, 0}, {0, 0, 0}, {0, 0, 1}, {0, 1, 1}}}; + break; + } - return chunk_to_ask->get(pos.x(), pos.y(), pos.z()); + for (auto& p : face) { + p += {x, y, z}; + } + return face; } -std::array<Vector<2, F32>, 4> face_tex_coords(BlockType type, BlockSide side) { +std::array<Vector<2, F32>, 4> DefaultMeshDecisions::face_tex_coords(BlockType type, BlockSide side) { U8 atlas_width = 4; U8 atlas_height = 4; @@ -56,75 +69,67 @@ std::array<Vector<2, F32>, 4> face_tex_coords(BlockType type, BlockSide side) { }; switch (type) { - case BlockType::Dirt: + case BlockType::Dirt: + return block_coords(1, 0); + case BlockType::Grass: + switch (side) { + case BlockSide::Front: + case BlockSide::Back: + case BlockSide::Left: + case BlockSide::Right: + return block_coords(2, 0); + case BlockSide::Bottom: return block_coords(1, 0); - case BlockType::Grass: - switch (side) { - case BlockSide::Front: - case BlockSide::Back: - case BlockSide::Left: - case BlockSide::Right: - return block_coords(2, 0); - case BlockSide::Bottom: - return block_coords(1, 0); - case BlockSide::Top: - return block_coords(0, 0); - } - case BlockType::Stone: - return block_coords(3, 0); - case BlockType::Sand: - return block_coords(1, 1); - case BlockType::Water: - return block_coords(0, 1); - case BlockType::Snow: - switch (side) { - case BlockSide::Front: - case BlockSide::Back: - case BlockSide::Left: - case BlockSide::Right: - return block_coords(3, 1); - case BlockSide::Bottom: - return block_coords(1, 0); - case BlockSide::Top: - return block_coords(2, 1); - } - case BlockType::Wood: - switch (side) { - case BlockSide::Front: - case BlockSide::Back: - case BlockSide::Right: - case BlockSide::Left: - return block_coords(0, 2); - case BlockSide::Bottom: - case BlockSide::Top: - return block_coords(1, 2); - } - case BlockType::Leaves: - return block_coords(2, 2); - case BlockType::Air: - return {}; + case BlockSide::Top: + return block_coords(0, 0); + } + case BlockType::Stone: + return block_coords(3, 0); + case BlockType::Sand: + return block_coords(1, 1); + case BlockType::Water: + return block_coords(0, 1); + case BlockType::Snow: + switch (side) { + case BlockSide::Front: + case BlockSide::Back: + case BlockSide::Left: + case BlockSide::Right: + return block_coords(3, 1); + case BlockSide::Bottom: + return block_coords(1, 0); + case BlockSide::Top: + return block_coords(2, 1); + } + case BlockType::Wood: + switch (side) { + case BlockSide::Front: + case BlockSide::Back: + case BlockSide::Right: + case BlockSide::Left: + return block_coords(0, 2); + case BlockSide::Bottom: + case BlockSide::Top: + return block_coords(1, 2); + } + case BlockType::Leaves: + return block_coords(2, 2); + case BlockType::Air: + return {}; } } -std::array<Vector<3, F32>, 4> face_normals(BlockSide side) { - auto is_side = [=](BlockSide s) -> Real { return s == side; }; - - Vector<3, F32> normal = { - is_side(BlockSide::Right) - is_side(BlockSide::Left), - is_side(BlockSide::Top) - is_side(BlockSide::Bottom), - is_side(BlockSide::Front) - is_side(BlockSide::Back), - }; - +std::array<Vector<3, F32>, 4> DefaultMeshDecisions::face_normals(BlockSide side) { + Vector<3, F32> normal{get_face_normal(side)}; return {normal, normal, normal, normal}; } -std::array<F32, 4> face_ao_values(Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side) { +std::array<F32, 4> DefaultMeshDecisions::face_ao_values(Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side) { std::array<Vector<3, I32>, 8> offsets{}; // Given a block position, these offsets can be added to it to get the 8 blocks necessary to calculate AO. // There are 4 corners and 4 sides, corners are visually distinguished by the lack of spaces and // but you can recognize them by the fact that they have no 0 offsets. // Note: Is there a way to compute these? I tried but I couldn't... If the vertex windings ever change again I don't want to hardcode these... - auto nowhere = Vector<3, I32>::max(); switch (side) { case BlockSide::Front: offsets = {{{0, 1, 1}, {-1,1,1}, {-1, 0, 1}, {-1,-1,1}, {0, -1, 1}, {1,-1,1}, {1, 0, 1}, {1,1,1}}}; @@ -172,80 +177,69 @@ std::array<F32, 4> face_ao_values(Chunk& chunk, const ChunkNeighbors& neighbors, return vertex_ao; } -Bool is_face_visible(Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side) { - Vector<3, I32> offset{}; - switch (side) { - case BlockSide::Front: - offset[2] = 1; - break; - case BlockSide::Back: - offset[2] = -1; - break; - case BlockSide::Top: - offset[1] = 1; - break; - case BlockSide::Bottom: - offset[1] = -1; - break; - case BlockSide::Right: - offset[0] = 1; - break; - case BlockSide::Left: - offset[0] = -1; - break; - } +Chunk::BlockData DefaultMeshDecisions::get_block_wrapping(const Chunk& chunk, const ChunkNeighbors& neighbors, Vector<3, I32> pos) { + const Chunk* chunk_to_ask; - Vector<3, I32> neighbor_pos{ - x + offset.x(), y + offset.y(), z + offset.z(), + auto overflow = [](I32& c, I32 max) -> I8 { + if (c < 0) { c += max; return -1; } + if (c >= max) { c -= max; return 1; } + return 0; }; - auto [neighbor] = get_block_wrapping(chunk, neighbors, neighbor_pos); - return neighbor.is_transparent(); + auto xo = overflow(pos.x(), Chunk::Width); + auto yo = overflow(pos.y(), Chunk::Height); + auto zo = overflow(pos.z(), Chunk::Width); + + // Blocks above and below a chunk are always Air. + if (yo != 0) return {}; + + if (xo == 1 && zo == 1) { chunk_to_ask = neighbors.south_east; } + else if (xo == 1 && zo == -1) { chunk_to_ask = neighbors.north_east; } + else if (xo == -1 && zo == 1) { chunk_to_ask = neighbors.south_west; } + else if (xo == -1 && zo == -1) { chunk_to_ask = neighbors.north_west; } + else if (xo == 1) { chunk_to_ask = neighbors.east; } + else if (xo == -1) { chunk_to_ask = neighbors.west; } + else if (zo == 1) { chunk_to_ask = neighbors.south; } + else if (zo == -1) { chunk_to_ask = neighbors.north; } + else { chunk_to_ask = &chunk; } + + return chunk_to_ask->get(pos.x(), pos.y(), pos.z()); } -GFX::Mesh create_mesh_for_chunk(Chunk& chunk, const ChunkNeighbors& neighbors) { - std::vector<Vector<3, F32>> positions{}; - std::vector<Vector<3, F32>> normals{}; - std::vector<Vector<2, F32>> tex_coords{}; - std::vector<F32> ambient_occlusion_values{}; - std::vector<U32> indices{}; - - for (Int x = 0; x < Chunk::Width; x++) { - for (Int y = 0; y < Chunk::Height; y++) { - for (Int z = 0; z < Chunk::Width; z++) { - auto block = chunk.get(x, y, z); - if (block.empty()) - continue; - - for (auto side: BlockSide::all()) { - if (!is_face_visible(chunk, neighbors, x, y, z, side)) - continue; - - auto side_positions = side.face(); - auto side_normals = face_normals(side); - auto side_tex_coords = face_tex_coords(block.type, side); - auto side_ao = face_ao_values(chunk, neighbors, x, y, z, side); - - for (auto& position : side_positions) { - position = position + Vector<3, F32>{x, y, z}; - } - - U32 s = positions.size(); - - positions.insert(positions.end(), side_positions.begin(), side_positions.end()); - normals.insert(normals.end(), side_normals.begin(), side_normals.end()); - tex_coords.insert(tex_coords.end(), side_tex_coords.begin(), side_tex_coords.end()); - ambient_occlusion_values.insert(ambient_occlusion_values.end(), side_ao.begin(), side_ao.end()); - indices.insert(indices.end(), {s + 0, s + 1, s + 2, s + 2, s + 3, s + 0 }); - } - } - } - } +Vector<3, I32> DefaultMeshDecisions::get_face_normal(BlockSide side) { + auto is_side = [=](BlockSide s) -> I8 { return s == side; }; return { - {positions, normals, tex_coords, ambient_occlusion_values}, - indices, + is_side(BlockSide::Right) - is_side(BlockSide::Left), + is_side(BlockSide::Top) - is_side(BlockSide::Bottom), + is_side(BlockSide::Front) - is_side(BlockSide::Back), }; } +Bool DefaultMeshDecisions::is_face_visible(Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side) { + Vector<3, I32> offset = get_face_normal(side); + auto neighbor_position = offset + Vector<3, I32>{x, y, z}; + + auto block = get_block_wrapping(chunk, neighbors, neighbor_position); + return block.type.is_transparent(); +} + +Bool DefaultMeshDecisions::should_ignore_block(Chunk::BlockData block) { + return block.empty() || block.type == BlockType::Water; +} + +Bool WaterMeshDecisions::is_face_visible(Chunk& chunk, const ChunkNeighbors& neighbors, U32 x, U32 y, U32 z, BlockSide side) { + Vector<3, I32> offset = get_face_normal(side); + auto neighbor_position = offset + Vector<3, I32>{x, y, z}; + + auto [neighbor] = get_block_wrapping(chunk, neighbors, neighbor_position); + return neighbor.is_transparent() && neighbor != BlockType::Water; +} + +Bool WaterMeshDecisions::should_ignore_block(Chunk::BlockData block) { + return block.type != BlockType::Water; +} + +} + } \ No newline at end of file |
