mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
perf:greedy meshing (#23)
* feat(gameplay): implement greedy meshing for chunk generation Replace the per-face vertex generation with a greedy meshing algorithm that merges adjacent faces of the same block type into larger quads. Introduce `FaceKey` struct and helper functions (`axis_dir_to_face`, `get_block_safe`, `is_face_culled`, `choose_buf`) to support the new algorithm. Comment out the old `gen_vertices` implementation. In texture management, rename `m_pbr_texture_array` to `m_normal_texture_array` to reflect its actual usage, and set texture wrap mode to `GL_REPEAT` for both the block and normal texture arrays. * fix(primitive_data): correct back face texture coordinates and tangents * fix(texture-manager): correct texture deletion and refactor reload Make hot_reload private and add public need_reload method. Update UI to call need_reload instead of hot_reload. Fix incorrect use of glDeleteBuffers for normal texture array by using glDeleteTextures.
This commit is contained in:
@@ -25,6 +25,18 @@ class Chunk {
|
|||||||
private:
|
private:
|
||||||
using OptionalBlockVectorArray =
|
using OptionalBlockVectorArray =
|
||||||
std::array<std::optional<std::vector<BlockType>>, 4>;
|
std::array<std::optional<std::vector<BlockType>>, 4>;
|
||||||
|
|
||||||
|
struct FaceKey {
|
||||||
|
BlockType block_id = 0;
|
||||||
|
int face = -1; // 0-5, used to index NORMALS/TANGENTS/TEX_COORDS
|
||||||
|
|
||||||
|
bool valid() const { return block_id != 0; }
|
||||||
|
bool operator==(const FaceKey& o) const {
|
||||||
|
return block_id == o.block_id && face == o.face;
|
||||||
|
}
|
||||||
|
bool operator!=(const FaceKey& o) const { return !(*this == o); }
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr int SIZE_X = CHUNK_SIZE;
|
static constexpr int SIZE_X = CHUNK_SIZE;
|
||||||
static constexpr int SIZE_Y = WORLD_SIZE_Y;
|
static constexpr int SIZE_Y = WORLD_SIZE_Y;
|
||||||
static constexpr int SIZE_Z = CHUNK_SIZE;
|
static constexpr int SIZE_Z = CHUNK_SIZE;
|
||||||
@@ -66,6 +78,8 @@ private:
|
|||||||
void gen_vertices(const OptionalBlockVectorArray& neighbor_block);
|
void gen_vertices(const OptionalBlockVectorArray& neighbor_block);
|
||||||
void gen_cross_plane_vertices(int world_x, int world_y, int world_z,
|
void gen_cross_plane_vertices(int world_x, int world_y, int world_z,
|
||||||
BlockType id);
|
BlockType id);
|
||||||
|
void emit_quad(int axis, int face_dir, int layer, int i, int j, int w,
|
||||||
|
int h, int u_axis, int v_axis, FaceKey key);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Chunk(World& world, ChunkPos chunk_pos, bool temp_chunk = false);
|
Chunk(World& world, ChunkPos chunk_pos, bool temp_chunk = false);
|
||||||
|
|||||||
@@ -63,12 +63,12 @@ constexpr float TEX_COORDS[6][6][2] = {
|
|||||||
{0.0f, 0.0f}, // top front
|
{0.0f, 0.0f}, // top front
|
||||||
{0.0f, 1.0f}}, // bottom front
|
{0.0f, 1.0f}}, // bottom front
|
||||||
// ===== back (z = -1) =====
|
// ===== back (z = -1) =====
|
||||||
{{1.0f, 1.0f}, // bottom left
|
{{0.0f, 1.0f}, // bottom left
|
||||||
{0.0f, 1.0f}, // bottom right
|
{0.0f, 0.0f}, // top left
|
||||||
{0.0f, 0.0f}, // top right
|
{1.0f, 0.0f}, // top right
|
||||||
{0.0f, 0.0f}, // top right
|
{1.0f, 0.0f}, // top right
|
||||||
{1.0f, 0.0f}, // top left
|
{1.0f, 1.0f}, // bottom right
|
||||||
{1.0f, 1.0f}}, // bottom left
|
{0.0f, 1.0f}}, // bottom left
|
||||||
// ===== left (x = -1) =====
|
// ===== left (x = -1) =====
|
||||||
{{1.0f, 1.0f}, // bottom back
|
{{1.0f, 1.0f}, // bottom back
|
||||||
{0.0f, 1.0f}, // bottom front
|
{0.0f, 1.0f}, // bottom front
|
||||||
@@ -152,12 +152,12 @@ constexpr float TANGENTS[6][6][3] = {
|
|||||||
{0.0f, 0.0f, -1.0f},
|
{0.0f, 0.0f, -1.0f},
|
||||||
{0.0f, 0.0f, -1.0f}},
|
{0.0f, 0.0f, -1.0f}},
|
||||||
// ===== back (z = -1) =====
|
// ===== back (z = -1) =====
|
||||||
{{-1.0f, 0.0f, 0.0f},
|
{{1.0f, 0.0f, 0.0f},
|
||||||
{-1.0f, 0.0f, 0.0f},
|
{1.0f, 0.0f, 0.0f},
|
||||||
{-1.0f, 0.0f, 0.0f},
|
{1.0f, 0.0f, 0.0f},
|
||||||
{-1.0f, 0.0f, 0.0f},
|
{1.0f, 0.0f, 0.0f},
|
||||||
{-1.0f, 0.0f, 0.0f},
|
{1.0f, 0.0f, 0.0f},
|
||||||
{-1.0f, 0.0f, 0.0f}},
|
{1.0f, 0.0f, 0.0f}},
|
||||||
// ===== left (x = -1) =====
|
// ===== left (x = -1) =====
|
||||||
{{0.0f, 0.0f, 1.0f},
|
{{0.0f, 0.0f, 1.0f},
|
||||||
{0.0f, 0.0f, 1.0f},
|
{0.0f, 0.0f, 1.0f},
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ private:
|
|||||||
GLuint m_texture_array = 0;
|
GLuint m_texture_array = 0;
|
||||||
GLuint m_cross_plane_array = 0;
|
GLuint m_cross_plane_array = 0;
|
||||||
GLuint m_ui_array = 0;
|
GLuint m_ui_array = 0;
|
||||||
GLuint m_pbr_texture_array = 0;
|
GLuint m_normal_texture_array = 0;
|
||||||
GLfloat m_max_aniso = 0.0f;
|
GLfloat m_max_aniso = 0.0f;
|
||||||
|
|
||||||
int m_aniso = 1;
|
int m_aniso = 1;
|
||||||
@@ -29,6 +29,7 @@ private:
|
|||||||
void init_block();
|
void init_block();
|
||||||
void init_ui();
|
void init_ui();
|
||||||
void init_block_status();
|
void init_block_status();
|
||||||
|
void hot_reload();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TextureManager();
|
TextureManager();
|
||||||
@@ -43,7 +44,7 @@ public:
|
|||||||
const std::vector<GLuint>& item_textures() const;
|
const std::vector<GLuint>& item_textures() const;
|
||||||
// Must call after MapTable::init_map() and glfwMakeContextCurrent(window);
|
// Must call after MapTable::init_map() and glfwMakeContextCurrent(window);
|
||||||
void init_texture();
|
void init_texture();
|
||||||
void hot_reload();
|
|
||||||
void need_reload();
|
void need_reload();
|
||||||
void update();
|
void update();
|
||||||
int max_aniso() const;
|
int max_aniso() const;
|
||||||
|
|||||||
@@ -430,7 +430,7 @@ void DevPanel::show_settings_tab_item() {
|
|||||||
}
|
}
|
||||||
if (ImGui::Button("ReloadTexture")) {
|
if (ImGui::Button("ReloadTexture")) {
|
||||||
Config::get().set("texture.aniso", m_config.aniso);
|
Config::get().set("texture.aniso", m_config.aniso);
|
||||||
m_app.texture_manager().hot_reload();
|
m_app.texture_manager().need_reload();
|
||||||
m_config.is_reload = true;
|
m_config.is_reload = true;
|
||||||
}
|
}
|
||||||
if (!m_config.is_reload) {
|
if (!m_config.is_reload) {
|
||||||
|
|||||||
@@ -7,6 +7,99 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
using OptionalBlockVectorArray =
|
||||||
|
std::array<std::optional<std::vector<BlockType>>, 4>;
|
||||||
|
namespace {
|
||||||
|
// ────────────────────────────────────────────────────────────────────────────
|
||||||
|
// Face direction mapping
|
||||||
|
// Original DIR[6]: {+Z,+X,-Z,-X,+Y,-Y} => face index 0-5
|
||||||
|
// Axis × direction => face:
|
||||||
|
// axis=2(Z) dir=+1 => face 0 (+Z)
|
||||||
|
// axis=0(X) dir=+1 => face 1 (+X)
|
||||||
|
// axis=2(Z) dir=-1 => face 2 (-Z)
|
||||||
|
// axis=0(X) dir=-1 => face 3 (-X)
|
||||||
|
// axis=1(Y) dir=+1 => face 4 (+Y)
|
||||||
|
// axis=1(Y) dir=-1 => face 5 (-Y)
|
||||||
|
// ────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
inline int axis_dir_to_face(int axis, int dir) {
|
||||||
|
// axis: 0=X 1=Y 2=Z
|
||||||
|
// dir: +1 or -1
|
||||||
|
static const int TABLE[3][2] = {
|
||||||
|
{3, 1}, // X: dir=-1->face3(-X), dir=+1->face1(+X)
|
||||||
|
{5, 4}, // Y: dir=-1->face5(-Y), dir=+1->face4(+Y)
|
||||||
|
{2, 0}, // Z: dir=-1->face2(-Z), dir=+1->face0(+Z)
|
||||||
|
};
|
||||||
|
return TABLE[axis][dir > 0 ? 1 : 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline BlockType
|
||||||
|
get_block_safe(int lx, int ly, int lz, ChunkPos& chunk_pos,
|
||||||
|
const std::vector<BlockType>& blocks,
|
||||||
|
const OptionalBlockVectorArray& neighbor_block) {
|
||||||
|
if (lx >= 0 && lx < CHUNK_SIZE && ly >= 0 && ly < WORLD_SIZE_Y && lz >= 0 &&
|
||||||
|
lz < CHUNK_SIZE) {
|
||||||
|
return blocks[Chunk::index(lx, ly, lz)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Out of bounds: check neighbors
|
||||||
|
int world_x = lx + chunk_pos.x * CHUNK_SIZE;
|
||||||
|
int world_z = lz + chunk_pos.z * CHUNK_SIZE;
|
||||||
|
|
||||||
|
auto [nb_cx, nb_cz] = World::get_chunk_pos(world_x, world_z);
|
||||||
|
|
||||||
|
const std::optional<std::vector<BlockType>>* nb = nullptr;
|
||||||
|
if (nb_cx == chunk_pos.x + 1)
|
||||||
|
nb = &neighbor_block[0];
|
||||||
|
else if (nb_cx == chunk_pos.x - 1)
|
||||||
|
nb = &neighbor_block[1];
|
||||||
|
else if (nb_cz == chunk_pos.z + 1)
|
||||||
|
nb = &neighbor_block[2];
|
||||||
|
else if (nb_cz == chunk_pos.z - 1)
|
||||||
|
nb = &neighbor_block[3];
|
||||||
|
|
||||||
|
if (!nb || !nb->has_value())
|
||||||
|
return 0; // Neighbor does not exist, treat as opaque
|
||||||
|
|
||||||
|
int nbx = world_x - nb_cx * CHUNK_SIZE;
|
||||||
|
int nby = ly;
|
||||||
|
int nbz = world_z - nb_cz * CHUNK_SIZE;
|
||||||
|
|
||||||
|
if (nbx < 0 || nby < 0 || nbz < 0 || nbx >= CHUNK_SIZE ||
|
||||||
|
nby >= WORLD_SIZE_Y || nbz >= CHUNK_SIZE)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int idx = Chunk::index(nbx, nby, nbz);
|
||||||
|
if (static_cast<size_t>(idx) >= (*nb)->size()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (**nb)[idx];
|
||||||
|
}
|
||||||
|
// Determine whether the face from cur_id looking towards neighbor_id should be
|
||||||
|
// culled (does not need to be rendered)
|
||||||
|
inline bool is_face_culled(BlockType cur_id, BlockType neighbor_id) {
|
||||||
|
if (!BlockManager::is_transparent(neighbor_id))
|
||||||
|
return true; // Neighbor is opaque, blocking
|
||||||
|
// Neighbor transparency: same block type culls each other (e.g., water
|
||||||
|
// adjacent to water does not render internal faces)
|
||||||
|
if (neighbor_id == cur_id)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int choose_buf(BlockType id) {
|
||||||
|
if (!BlockManager::is_transparent(id))
|
||||||
|
return 0;
|
||||||
|
if (BlockManager::is_discard(id))
|
||||||
|
return 2;
|
||||||
|
if (BlockManager::is_blend(id)) {
|
||||||
|
return (id == 7) ? 4 : 3; // water=4, other blend=3
|
||||||
|
}
|
||||||
|
return 3; // fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
Chunk::Chunk(World& world, ChunkPos chunk_pos, bool temp_chunk)
|
Chunk::Chunk(World& world, ChunkPos chunk_pos, bool temp_chunk)
|
||||||
: m_temp_chunk(temp_chunk), m_chunk_pos(chunk_pos), m_world(world) {
|
: m_temp_chunk(temp_chunk), m_chunk_pos(chunk_pos), m_world(world) {
|
||||||
@@ -276,7 +369,7 @@ ChunkInfo Chunk::get_info() const {
|
|||||||
}
|
}
|
||||||
return m_info;
|
return m_info;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
void Chunk::gen_vertices(const OptionalBlockVectorArray& neighbor_block) {
|
void Chunk::gen_vertices(const OptionalBlockVectorArray& neighbor_block) {
|
||||||
static const glm::ivec3 DIR[6] = {{0, 0, 1}, {1, 0, 0}, {0, 0, -1},
|
static const glm::ivec3 DIR[6] = {{0, 0, 1}, {1, 0, 0}, {0, 0, -1},
|
||||||
{-1, 0, 0}, {0, 1, 0}, {0, -1, 0}};
|
{-1, 0, 0}, {0, 1, 0}, {0, -1, 0}};
|
||||||
@@ -432,6 +525,201 @@ void Chunk::gen_vertices(const OptionalBlockVectorArray& neighbor_block) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
void Chunk::gen_vertices(const OptionalBlockVectorArray& neighbor_block) {
|
||||||
|
|
||||||
|
// SIZE_X=SIZE_Z=CHUNK_SIZE=16, SIZE_Y=WORLD_SIZE_Y=256
|
||||||
|
// Axis order: axis 0=X, 1=Y, 2=Z
|
||||||
|
// Two slice dimensions of each axis
|
||||||
|
const int DIMS[3] = {CHUNK_SIZE, WORLD_SIZE_Y, CHUNK_SIZE};
|
||||||
|
|
||||||
|
// Maximum mask size: max(16*256, 16*16) = 4096
|
||||||
|
static thread_local FaceKey mask[CHUNK_SIZE * WORLD_SIZE_Y];
|
||||||
|
static thread_local bool visited[CHUNK_SIZE * WORLD_SIZE_Y];
|
||||||
|
|
||||||
|
for (int axis = 0; axis < 3; axis++) {
|
||||||
|
int u_axis = (axis + 1) % 3; // horizontal
|
||||||
|
int v_axis = (axis + 2) % 3; // vertical
|
||||||
|
|
||||||
|
int u = DIMS[u_axis];
|
||||||
|
int v = DIMS[v_axis];
|
||||||
|
int d = DIMS[axis]; // Depth along the normal axis
|
||||||
|
|
||||||
|
for (int face_dir : {1, -1}) {
|
||||||
|
int face_idx = axis_dir_to_face(axis, face_dir);
|
||||||
|
|
||||||
|
for (int layer = 0; layer < d; layer++) {
|
||||||
|
|
||||||
|
// ── 1. Build mask ──────────────────────────────────────────
|
||||||
|
for (int vi = 0; vi < v; vi++) {
|
||||||
|
for (int ui = 0; ui < u; ui++) {
|
||||||
|
// Current cell local coordinates
|
||||||
|
int lpos[3];
|
||||||
|
lpos[axis] = layer;
|
||||||
|
lpos[u_axis] = ui;
|
||||||
|
lpos[v_axis] = vi;
|
||||||
|
|
||||||
|
// Neighbor (offset one cell along the normal direction)
|
||||||
|
int npos[3];
|
||||||
|
npos[axis] = layer + face_dir;
|
||||||
|
npos[u_axis] = ui;
|
||||||
|
npos[v_axis] = vi;
|
||||||
|
|
||||||
|
BlockType cur_id = get_block_safe(
|
||||||
|
lpos[0], lpos[1], lpos[2], m_chunk_pos, m_blocks,
|
||||||
|
neighbor_block);
|
||||||
|
|
||||||
|
// Air / cross plane are not involved in greedy meshing
|
||||||
|
if (cur_id == 0 ||
|
||||||
|
BlockManager::is_cross_plane(cur_id)) {
|
||||||
|
mask[vi * u + ui] = {};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockType nb_id = get_block_safe(
|
||||||
|
npos[0], npos[1], npos[2], m_chunk_pos, m_blocks,
|
||||||
|
neighbor_block);
|
||||||
|
|
||||||
|
if (is_face_culled(cur_id, nb_id)) {
|
||||||
|
mask[vi * u + ui] = {};
|
||||||
|
} else {
|
||||||
|
mask[vi * u + ui] = {cur_id, face_idx};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── 2. Greedy Merge ──────────────────────────────────────
|
||||||
|
std::fill(visited, visited + u * v, false);
|
||||||
|
|
||||||
|
for (int vi = 0; vi < v; vi++) {
|
||||||
|
for (int ui = 0; ui < u; ui++) {
|
||||||
|
if (visited[vi * u + ui])
|
||||||
|
continue;
|
||||||
|
FaceKey cur = mask[vi * u + ui];
|
||||||
|
if (!cur.valid())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Extend width in the u direction
|
||||||
|
int w = 1;
|
||||||
|
while (ui + w < u && !visited[vi * u + (ui + w)] &&
|
||||||
|
mask[vi * u + (ui + w)] == cur) {
|
||||||
|
w++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extend height in the v direction
|
||||||
|
int h = 1;
|
||||||
|
bool can_expand = true;
|
||||||
|
while (vi + h < v && can_expand) {
|
||||||
|
for (int k = 0; k < w; k++) {
|
||||||
|
int idx = (vi + h) * u + (ui + k);
|
||||||
|
if (visited[idx] || mask[idx] != cur) {
|
||||||
|
can_expand = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (can_expand)
|
||||||
|
h++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark visited
|
||||||
|
for (int dv = 0; dv < h; dv++)
|
||||||
|
for (int du = 0; du < w; du++)
|
||||||
|
visited[(vi + dv) * u + (ui + du)] = true;
|
||||||
|
|
||||||
|
// output quad
|
||||||
|
emit_quad(axis, face_dir, layer, ui, vi, w, h, u_axis,
|
||||||
|
v_axis, cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int x = 0; x < CHUNK_SIZE; x++) {
|
||||||
|
for (int y = 0; y < WORLD_SIZE_Y; y++) {
|
||||||
|
for (int z = 0; z < CHUNK_SIZE; z++) {
|
||||||
|
BlockType id = m_blocks[index(x, y, z)];
|
||||||
|
if (id != 0 && BlockManager::is_cross_plane(id)) {
|
||||||
|
int world_x = x + m_chunk_pos.x * CHUNK_SIZE;
|
||||||
|
int world_z = z + m_chunk_pos.z * CHUNK_SIZE;
|
||||||
|
gen_cross_plane_vertices(world_x, y, world_z, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Chunk::emit_quad(int axis, int face_dir, int layer, int i, int j, int w,
|
||||||
|
int h, int u_axis, int v_axis, FaceKey key) {
|
||||||
|
float axis_val = (float)(layer + (face_dir > 0 ? 1 : 0));
|
||||||
|
float wx_base = (float)(m_chunk_pos.x * CHUNK_SIZE);
|
||||||
|
float wz_base = (float)(m_chunk_pos.z * CHUNK_SIZE);
|
||||||
|
|
||||||
|
// Offsets of the four corners along the u_axis/v_axis
|
||||||
|
int su[4] = {0, w, w, 0};
|
||||||
|
int sv[4] = {0, 0, h, h};
|
||||||
|
|
||||||
|
// Each face's UV: directly read from the four corners of TEX_COORDS, then
|
||||||
|
// scaled by w/h TEX_COORDS vertex order: 0=BL, 1=TL, 2=TR, 3=TR, 4=BR, 5=BL
|
||||||
|
// (two triangles) Four unique corners correspond to indices: BL=0, TL=1,
|
||||||
|
// TR=2, BR=4 Extract the UVs of the four corners from TEX_COORDS (unique
|
||||||
|
// corners after removing duplicate vertices) Vertices 0,1,2,4 correspond to
|
||||||
|
// BL, TL, TR, BR
|
||||||
|
float u0 = TEX_COORDS[key.face][0][0]; // BL.u
|
||||||
|
float v0 = TEX_COORDS[key.face][0][1]; // BL.v
|
||||||
|
float u1 = TEX_COORDS[key.face][4][0]; // BR.u
|
||||||
|
float v1 = TEX_COORDS[key.face][4][1]; // BR.v
|
||||||
|
float u3 = TEX_COORDS[key.face][1][0]; // TL.u
|
||||||
|
float v3 = TEX_COORDS[key.face][1][1]; // TL.v
|
||||||
|
|
||||||
|
float du_u = u1 - u0; // Change in u when su increases (per block)
|
||||||
|
float dv_u = v1 - v0;
|
||||||
|
float du_v = u3 - u0; // Change in u when sv increases
|
||||||
|
float dv_v = v3 - v0;
|
||||||
|
|
||||||
|
float uvs[4][2] = {
|
||||||
|
{u0, v0}, // (0, 0 )
|
||||||
|
{u0 + du_u * (float)w, v0 + dv_u * (float)w}, // (w, 0 )
|
||||||
|
{u0 + du_u * (float)w + du_v * (float)h,
|
||||||
|
v0 + dv_u * (float)w + dv_v * (float)h}, // (w, h )
|
||||||
|
{u0 + du_v * (float)h, v0 + dv_v * (float)h}, // (0, h )
|
||||||
|
};
|
||||||
|
|
||||||
|
int tri[6] = {0, 1, 2, 0, 2, 3};
|
||||||
|
|
||||||
|
float pos[4][3];
|
||||||
|
for (int c = 0; c < 4; c++) {
|
||||||
|
pos[c][axis] = axis_val;
|
||||||
|
pos[c][u_axis] = (float)(i + su[c]);
|
||||||
|
pos[c][v_axis] = (float)(j + sv[c]);
|
||||||
|
pos[c][0] += wx_base;
|
||||||
|
pos[c][2] += wz_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
float layer_id = (float)(key.block_id * 6 + key.face);
|
||||||
|
float roughness = BlockManager::roughness(key.block_id);
|
||||||
|
int buf = choose_buf(key.block_id);
|
||||||
|
|
||||||
|
for (int vi = 0; vi < 6; vi++) {
|
||||||
|
int c = tri[vi];
|
||||||
|
Vertex3D vex = {
|
||||||
|
pos[c][0],
|
||||||
|
pos[c][1],
|
||||||
|
pos[c][2],
|
||||||
|
uvs[c][0],
|
||||||
|
uvs[c][1],
|
||||||
|
layer_id,
|
||||||
|
NORMALS[key.face][0][0],
|
||||||
|
NORMALS[key.face][0][1],
|
||||||
|
NORMALS[key.face][0][2],
|
||||||
|
roughness,
|
||||||
|
TANGENTS[key.face][0][0],
|
||||||
|
TANGENTS[key.face][0][1],
|
||||||
|
TANGENTS[key.face][0][2],
|
||||||
|
};
|
||||||
|
m_vertex_data[buf].m_vertices.emplace_back(vex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Chunk::gen_cross_plane_vertices(int world_x, int world_y, int world_z,
|
void Chunk::gen_cross_plane_vertices(int world_x, int world_y, int world_z,
|
||||||
BlockType id) {
|
BlockType id) {
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ void TextureManager::delet_texture() {
|
|||||||
glDeleteTextures(1, &m_texture_array);
|
glDeleteTextures(1, &m_texture_array);
|
||||||
glDeleteTextures(1, &m_block_status_array);
|
glDeleteTextures(1, &m_block_status_array);
|
||||||
glDeleteTextures(1, &m_cross_plane_array);
|
glDeleteTextures(1, &m_cross_plane_array);
|
||||||
glDeleteBuffers(1, &m_pbr_texture_array);
|
glDeleteTextures(1, &m_normal_texture_array);
|
||||||
for (auto& id : m_item_textures) {
|
for (auto& id : m_item_textures) {
|
||||||
glDeleteTextures(1, &id);
|
glDeleteTextures(1, &id);
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,9 @@ GLuint TextureManager::get_cross_plane_array() const {
|
|||||||
}
|
}
|
||||||
GLuint TextureManager::get_ui_array() const { return m_ui_array; }
|
GLuint TextureManager::get_ui_array() const { return m_ui_array; }
|
||||||
|
|
||||||
GLuint TextureManager::get_pbr_texture() const { return m_pbr_texture_array; }
|
GLuint TextureManager::get_pbr_texture() const {
|
||||||
|
return m_normal_texture_array;
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<GLuint>& TextureManager::item_textures() const {
|
const std::vector<GLuint>& TextureManager::item_textures() const {
|
||||||
return m_item_textures;
|
return m_item_textures;
|
||||||
@@ -181,7 +183,7 @@ void TextureManager::load_pbr_texture(unsigned id) {
|
|||||||
image_data[4] = (Tools::load_image_data(path + "/top_n.png", false));
|
image_data[4] = (Tools::load_image_data(path + "/top_n.png", false));
|
||||||
image_data[5] = (Tools::load_image_data(path + "/base_n.png", false));
|
image_data[5] = (Tools::load_image_data(path + "/base_n.png", false));
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, m_pbr_texture_array);
|
glBindTexture(GL_TEXTURE_2D_ARRAY, m_normal_texture_array);
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
unsigned char* data = image_data[i];
|
unsigned char* data = image_data[i];
|
||||||
bool is_fallback = false;
|
bool is_fallback = false;
|
||||||
@@ -213,8 +215,8 @@ void TextureManager::init_block() {
|
|||||||
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, CROSS_PLANE_SIZE,
|
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, CROSS_PLANE_SIZE,
|
||||||
CROSS_PLANE_SIZE, BlockManager::cross_plane_sum(), 0, GL_RGBA,
|
CROSS_PLANE_SIZE, BlockManager::cross_plane_sum(), 0, GL_RGBA,
|
||||||
GL_UNSIGNED_BYTE, nullptr);
|
GL_UNSIGNED_BYTE, nullptr);
|
||||||
glGenTextures(1, &m_pbr_texture_array);
|
glGenTextures(1, &m_normal_texture_array);
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, m_pbr_texture_array);
|
glBindTexture(GL_TEXTURE_2D_ARRAY, m_normal_texture_array);
|
||||||
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, BLOCK_NORMAL_SIZE,
|
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, BLOCK_NORMAL_SIZE,
|
||||||
BLOCK_NORMAL_SIZE, BlockManager::sums() * 6, 0, GL_RGBA,
|
BLOCK_NORMAL_SIZE, BlockManager::sums() * 6, 0, GL_RGBA,
|
||||||
GL_UNSIGNED_BYTE, nullptr);
|
GL_UNSIGNED_BYTE, nullptr);
|
||||||
@@ -228,6 +230,8 @@ void TextureManager::init_block() {
|
|||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,
|
||||||
GL_LINEAR_MIPMAP_LINEAR);
|
GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
||||||
if (m_aniso >= 1) {
|
if (m_aniso >= 1) {
|
||||||
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY,
|
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY,
|
||||||
@@ -246,12 +250,12 @@ void TextureManager::init_block() {
|
|||||||
static_cast<GLfloat>(m_aniso));
|
static_cast<GLfloat>(m_aniso));
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D_ARRAY, m_pbr_texture_array);
|
glBindTexture(GL_TEXTURE_2D_ARRAY, m_normal_texture_array);
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,
|
||||||
GL_LINEAR_MIPMAP_LINEAR);
|
GL_LINEAR_MIPMAP_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
||||||
if (m_aniso >= 1) {
|
if (m_aniso >= 1) {
|
||||||
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY,
|
glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY,
|
||||||
|
|||||||
Reference in New Issue
Block a user