mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-06-18 00:27:02 +08:00
feat(rendering): separate transparent blocks into discard and blend modes
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
id = 0
|
||||
is_blend = false
|
||||
is_cross_plane = false
|
||||
is_discard = true
|
||||
is_gas = true
|
||||
is_liquid = false
|
||||
is_passable = true
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
id = 2
|
||||
is_blend = false
|
||||
is_cross_plane = false
|
||||
is_discard = false
|
||||
is_gas = false
|
||||
is_liquid = false
|
||||
is_passable = false
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
id = 9
|
||||
is_blend = false
|
||||
is_cross_plane = true
|
||||
is_discard = true
|
||||
is_gas = false
|
||||
is_liquid = false
|
||||
is_passable = true
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
id = 1
|
||||
is_blend = false
|
||||
is_cross_plane = false
|
||||
is_discard = false
|
||||
is_gas = false
|
||||
is_liquid = false
|
||||
is_passable = false
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
id = 6
|
||||
is_blend = false
|
||||
is_cross_plane = false
|
||||
is_discard = true
|
||||
is_gas = false
|
||||
is_liquid = false
|
||||
is_passable = false
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
id = 5
|
||||
is_blend = false
|
||||
is_cross_plane = false
|
||||
is_discard = false
|
||||
is_gas = false
|
||||
is_liquid = false
|
||||
is_passable = false
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
id = 4
|
||||
is_blend = false
|
||||
is_cross_plane = false
|
||||
is_discard = false
|
||||
is_gas = false
|
||||
is_liquid = false
|
||||
is_passable = false
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
id = 8
|
||||
is_blend = false
|
||||
is_cross_plane = false
|
||||
is_discard = false
|
||||
is_gas = false
|
||||
is_liquid = false
|
||||
is_passable = false
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
id = 3
|
||||
is_blend = false
|
||||
is_cross_plane = false
|
||||
is_discard = false
|
||||
is_gas = false
|
||||
is_liquid = false
|
||||
is_passable = false
|
||||
|
||||
@@ -5,3 +5,5 @@ is_gas = false
|
||||
is_passable = false
|
||||
is_cross_plane = false
|
||||
is_transparent = false
|
||||
is_discard = false
|
||||
is_blend = false
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
id = 7
|
||||
is_blend = true
|
||||
is_cross_plane = false
|
||||
is_discard = false
|
||||
is_gas = false
|
||||
is_liquid = true
|
||||
is_passable = true
|
||||
|
||||
@@ -8,7 +8,7 @@ layout (binding = 0) uniform sampler2DArray samp;
|
||||
|
||||
void main(void) {
|
||||
color = texture(samp, vec3(tc, tex_layer));
|
||||
if (color.a < 0.1) {
|
||||
if (color.a < 0.45) {
|
||||
discard;
|
||||
}
|
||||
//color = varyingColor;
|
||||
|
||||
@@ -47,11 +47,16 @@ struct BlockData {
|
||||
bool is_passable = false;
|
||||
bool is_cross_plane = false;
|
||||
bool is_transparent = false;
|
||||
|
||||
bool is_discard = false;
|
||||
bool is_blend = false;
|
||||
|
||||
BlockData(BlockType b_id, std::string_view b_name, bool liquid,
|
||||
bool passable, bool cross_plane, bool transparent, bool gas)
|
||||
bool passable, bool cross_plane, bool transparent, bool gas,
|
||||
bool discard, bool blend)
|
||||
: name(b_name), id(b_id), is_liquid(liquid), is_gas(gas),
|
||||
is_passable(passable), is_cross_plane(cross_plane),
|
||||
is_transparent(transparent) {}
|
||||
is_transparent(transparent), is_discard(discard), is_blend(blend) {}
|
||||
};
|
||||
|
||||
class BlockManager {
|
||||
@@ -69,6 +74,10 @@ public:
|
||||
static bool is_cross_plane(BlockType id);
|
||||
static bool is_transparent(BlockType id);
|
||||
static bool is_passable(BlockType id);
|
||||
|
||||
static bool is_discard(BlockType id);
|
||||
static bool is_blend(BlockType id);
|
||||
|
||||
static BlockType cross_plane_index(BlockType id);
|
||||
|
||||
private:
|
||||
|
||||
@@ -17,7 +17,7 @@ private:
|
||||
static constexpr int SIZE_X = CHUNK_SIZE;
|
||||
static constexpr int SIZE_Y = WORLD_SIZE_Y;
|
||||
static constexpr int SIZE_Z = CHUNK_SIZE;
|
||||
|
||||
static constexpr int VERTEX_DATA_SUM = 4;
|
||||
std::atomic<bool> m_dirty{false};
|
||||
std::atomic<bool> m_need_upload{true};
|
||||
std::atomic<bool> m_is_on_gen_vertex_data{false};
|
||||
@@ -35,7 +35,8 @@ private:
|
||||
/*
|
||||
0 - normal
|
||||
1 - cross_plane
|
||||
2 - transparent
|
||||
2 - normal_discard
|
||||
3 - transparent and blend
|
||||
*/
|
||||
std::vector<VertexData> m_vertex_data;
|
||||
float frequency = 0.01f;
|
||||
@@ -45,9 +46,10 @@ private:
|
||||
BiomeConditions m_conditions;
|
||||
|
||||
void clear_dirty();
|
||||
void gen_normal_vertices(
|
||||
void gen_vertices(
|
||||
const std::array<const std::vector<BlockType>*, 4>& neighbor_block);
|
||||
void gen_cross_plane_vertices();
|
||||
void gen_cross_plane_vertices(int world_x, int world_y, int world_z,
|
||||
BlockType id);
|
||||
|
||||
public:
|
||||
Chunk(World& world, ChunkPos chunk_pos);
|
||||
@@ -105,8 +107,11 @@ public:
|
||||
GLuint get_cross_vbo() const;
|
||||
size_t get_cross_vertices_sum() const;
|
||||
|
||||
GLuint get_transparent_vbo() const;
|
||||
size_t get_transparent_vertices_sum() const;
|
||||
GLuint get_normal_discard_vbo() const;
|
||||
size_t get_normal_discard_vertices_sum() const;
|
||||
|
||||
GLuint get_normal_blend_vbo() const;
|
||||
size_t get_normal_blend_vertices_sum() const;
|
||||
|
||||
bool is_dirty() const;
|
||||
void mark_dirty();
|
||||
|
||||
@@ -19,8 +19,10 @@ struct ChunkRenderSnapshot {
|
||||
size_t normal_vertices_count;
|
||||
GLuint cross_vbo;
|
||||
size_t cross_vertices_count;
|
||||
GLuint transparent_vbo;
|
||||
size_t transparent_vertices_count;
|
||||
GLuint normal_discard_vbo;
|
||||
size_t normal_discard_vertices_count;
|
||||
GLuint normal_blend_vbo;
|
||||
size_t normal_blend_vertices_count;
|
||||
glm::vec3 center;
|
||||
glm::vec3 half_extents;
|
||||
};
|
||||
|
||||
@@ -90,6 +90,21 @@ bool BlockManager::is_passable(BlockType id) {
|
||||
return m_datas[id].is_passable;
|
||||
}
|
||||
|
||||
bool BlockManager::is_discard(BlockType id) {
|
||||
if (id >= sums()) {
|
||||
Logger::error("Id {}, is Over The Max Id", id, sums() - 1);
|
||||
return m_datas[0].is_discard;
|
||||
}
|
||||
return m_datas[id].is_discard;
|
||||
}
|
||||
bool BlockManager::is_blend(BlockType id) {
|
||||
if (id >= sums()) {
|
||||
Logger::error("Id {}, is Over The Max Id", id, sums() - 1);
|
||||
return m_datas[0].is_blend;
|
||||
}
|
||||
return m_datas[id].is_blend;
|
||||
}
|
||||
|
||||
void BlockManager::init() {
|
||||
fs::path data_path{block_data_dir};
|
||||
|
||||
@@ -125,8 +140,11 @@ void BlockManager::init() {
|
||||
auto is_cross_plane = safe_get_value(block, "is_cross_plane", false);
|
||||
auto is_transparent = safe_get_value(block, "is_transparent", false);
|
||||
auto is_gas = safe_get_value(block, "is_gas", false);
|
||||
auto is_discard = safe_get_value(block, "is_discard", false);
|
||||
auto is_blend = safe_get_value(block, "is_blend", false);
|
||||
m_datas.emplace_back(*id, *name, *is_liquid, *is_passable,
|
||||
*is_cross_plane, *is_transparent, *is_gas);
|
||||
*is_cross_plane, *is_transparent, *is_gas,
|
||||
*is_discard, *is_blend);
|
||||
}
|
||||
std::sort(
|
||||
m_datas.begin(), m_datas.end(),
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Cubed {
|
||||
|
||||
Chunk::Chunk(World& world, ChunkPos chunk_pos)
|
||||
: m_chunk_pos(chunk_pos), m_world(world) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int i = 0; i < VERTEX_DATA_SUM; i++) {
|
||||
m_vertex_data.emplace_back(m_world);
|
||||
}
|
||||
}
|
||||
@@ -115,8 +115,7 @@ void Chunk::gen_vertex_data(
|
||||
data.m_vertices.clear();
|
||||
}
|
||||
|
||||
gen_normal_vertices(neighbor_block);
|
||||
gen_cross_plane_vertices();
|
||||
gen_vertices(neighbor_block);
|
||||
for (auto& data : m_vertex_data) {
|
||||
data.update_sum();
|
||||
}
|
||||
@@ -138,11 +137,16 @@ size_t Chunk::get_cross_vertices_sum() const {
|
||||
return m_vertex_data[1].m_sum.load();
|
||||
}
|
||||
|
||||
GLuint Chunk::get_transparent_vbo() const { return m_vertex_data[2].m_vbo; }
|
||||
size_t Chunk::get_transparent_vertices_sum() const {
|
||||
GLuint Chunk::get_normal_discard_vbo() const { return m_vertex_data[2].m_vbo; }
|
||||
size_t Chunk::get_normal_discard_vertices_sum() const {
|
||||
return m_vertex_data[2].m_sum.load();
|
||||
}
|
||||
|
||||
GLuint Chunk::get_normal_blend_vbo() const { return m_vertex_data[3].m_vbo; }
|
||||
size_t Chunk::get_normal_blend_vertices_sum() const {
|
||||
return m_vertex_data[3].m_sum.load();
|
||||
}
|
||||
|
||||
void Chunk::gen_phase_one() {
|
||||
m_generator = std::make_unique<ChunkGenerator>(*this);
|
||||
if (!m_generator) {
|
||||
@@ -258,7 +262,7 @@ unsigned Chunk::seed() const {
|
||||
|
||||
BiomeConditions& Chunk::conditions() { return m_conditions; }
|
||||
|
||||
void Chunk::gen_normal_vertices(
|
||||
void Chunk::gen_vertices(
|
||||
const std::array<const std::vector<BlockType>*, 4>& neighbor_block) {
|
||||
static const glm::ivec3 DIR[6] = {{0, 0, 1}, {1, 0, 0}, {0, 0, -1},
|
||||
{-1, 0, 0}, {0, 1, 0}, {0, -1, 0}};
|
||||
@@ -355,6 +359,10 @@ void Chunk::gen_normal_vertices(
|
||||
if (neighbor_culled) {
|
||||
continue;
|
||||
}
|
||||
if (BlockManager::is_cross_plane(cur_id)) {
|
||||
gen_cross_plane_vertices(world_x, world_y, world_z,
|
||||
cur_id);
|
||||
}
|
||||
for (int i = 0; i < 6; i++) {
|
||||
Vertex vex = {
|
||||
VERTICES_POS[face][i][0] + (float)world_x * 1.0f,
|
||||
@@ -366,7 +374,17 @@ void Chunk::gen_normal_vertices(
|
||||
|
||||
};
|
||||
if (BlockManager::is_transparent(cur_id)) {
|
||||
if (BlockManager::is_discard(cur_id)) {
|
||||
m_vertex_data[2].m_vertices.emplace_back(vex);
|
||||
} else if (BlockManager::is_blend(cur_id)) {
|
||||
m_vertex_data[3].m_vertices.emplace_back(vex);
|
||||
} else {
|
||||
Logger::warn("Id {} is transparent but not "
|
||||
"discard or blend",
|
||||
cur_id);
|
||||
m_vertex_data[3].m_vertices.emplace_back(vex);
|
||||
}
|
||||
|
||||
} else {
|
||||
m_vertex_data[0].m_vertices.emplace_back(vex);
|
||||
}
|
||||
@@ -376,40 +394,30 @@ void Chunk::gen_normal_vertices(
|
||||
}
|
||||
}
|
||||
}
|
||||
void Chunk::gen_cross_plane_vertices() {
|
||||
|
||||
for (int x = 0; x < SIZE_X; x++) {
|
||||
for (int y = 0; y < SIZE_Y; y++) {
|
||||
for (int z = 0; z < SIZE_Z; z++) {
|
||||
int world_x = x + m_chunk_pos.x * CHUNK_SIZE;
|
||||
int world_z = z + m_chunk_pos.z * CHUNK_SIZE;
|
||||
int world_y = y;
|
||||
int id = m_blocks[index(x, y, z)];
|
||||
void Chunk::gen_cross_plane_vertices(int world_x, int world_y, int world_z,
|
||||
BlockType id) {
|
||||
|
||||
if (!BlockManager::is_cross_plane(id)) {
|
||||
continue;
|
||||
Logger::warn("Block {} {} {} id {} is not cross plane", world_x,
|
||||
world_y, world_z, id);
|
||||
return;
|
||||
}
|
||||
for (int face = 0; face < 2; face++) {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
Vertex vex = {CROSS_VERTICES_POS[face][i][0] +
|
||||
(float)world_x * 1.0f,
|
||||
CROSS_VERTICES_POS[face][i][1] +
|
||||
(float)world_y * 1.0f,
|
||||
CROSS_VERTICES_POS[face][i][2] +
|
||||
(float)world_z * 1.0f,
|
||||
Vertex vex = {
|
||||
CROSS_VERTICES_POS[face][i][0] + (float)world_x * 1.0f,
|
||||
CROSS_VERTICES_POS[face][i][1] + (float)world_y * 1.0f,
|
||||
CROSS_VERTICES_POS[face][i][2] + (float)world_z * 1.0f,
|
||||
CROSS_TEX_COORDS[face][i][0],
|
||||
CROSS_TEX_COORDS[face][i][1],
|
||||
static_cast<float>(
|
||||
BlockManager::cross_plane_index(id))
|
||||
static_cast<float>(BlockManager::cross_plane_index(id))
|
||||
|
||||
};
|
||||
m_vertex_data[1].m_vertices.emplace_back(vex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Logger::info("Cross Sum {}", m_cross_vertices_sum.load());
|
||||
}
|
||||
|
||||
} // namespace Cubed
|
||||
|
||||
@@ -319,46 +319,17 @@ void World::render(const glm::mat4& mvp_matrix,
|
||||
rendered_sum++;
|
||||
}
|
||||
}
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
struct SortableSnapshot {
|
||||
const ChunkRenderSnapshot* snapshot;
|
||||
float distance;
|
||||
};
|
||||
|
||||
std::vector<SortableSnapshot> cross_list;
|
||||
std::vector<SortableSnapshot> transparent_list;
|
||||
// cross_plane and normal discard
|
||||
|
||||
for (const auto& snapshot : m_render_snapshots) {
|
||||
|
||||
if (!is_aabb_in_frustum(snapshot.center, snapshot.half_extents)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float dist = glm::distance(camera_pos, snapshot.center);
|
||||
glm::vec2 camera_pos_xz{camera_pos.x, camera_pos.z};
|
||||
if (snapshot.cross_vertices_count != 0) {
|
||||
glm::vec2 center_xz{snapshot.center.x, snapshot.center.z};
|
||||
float dist2d = glm::distance(camera_pos_xz, center_xz);
|
||||
if (dist2d <= CROSS_PLANE_DISTANCE * 16) {
|
||||
cross_list.push_back({&snapshot, dist});
|
||||
}
|
||||
}
|
||||
if (snapshot.transparent_vertices_count != 0) {
|
||||
transparent_list.push_back({&snapshot, dist});
|
||||
}
|
||||
}
|
||||
std::sort(transparent_list.begin(), transparent_list.end(),
|
||||
[](const SortableSnapshot& a, const SortableSnapshot& b) {
|
||||
return a.distance > b.distance;
|
||||
});
|
||||
std::sort(cross_list.begin(), cross_list.end(),
|
||||
[](const SortableSnapshot& a, const SortableSnapshot& b) {
|
||||
return a.distance > b.distance;
|
||||
});
|
||||
|
||||
for (const auto& item : cross_list) {
|
||||
const auto& snapshot = *item.snapshot;
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY,
|
||||
texture_manager.get_cross_plane_array());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, snapshot.cross_vbo);
|
||||
@@ -376,11 +347,11 @@ void World::render(const glm::mat4& mvp_matrix,
|
||||
glDrawArrays(GL_TRIANGLES, 0, snapshot.cross_vertices_count);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
for (const auto& item : transparent_list) {
|
||||
const auto& snapshot = *item.snapshot;
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_manager.get_texture_array());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, snapshot.transparent_vbo);
|
||||
}
|
||||
if (snapshot.normal_discard_vertices_count != 0) {
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY,
|
||||
texture_manager.get_texture_array());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, snapshot.normal_discard_vbo);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
|
||||
(void*)0);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
|
||||
@@ -392,7 +363,55 @@ void World::render(const glm::mat4& mvp_matrix,
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, snapshot.transparent_vertices_count);
|
||||
glDrawArrays(GL_TRIANGLES, 0,
|
||||
snapshot.normal_discard_vertices_count);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// blend block
|
||||
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
struct SortableSnapshot {
|
||||
const ChunkRenderSnapshot* snapshot;
|
||||
float distance;
|
||||
};
|
||||
|
||||
std::vector<SortableSnapshot> blend_list;
|
||||
|
||||
for (const auto& snapshot : m_render_snapshots) {
|
||||
|
||||
if (!is_aabb_in_frustum(snapshot.center, snapshot.half_extents)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float dist = glm::distance(camera_pos, snapshot.center);
|
||||
if (snapshot.normal_blend_vertices_count != 0) {
|
||||
blend_list.push_back({&snapshot, dist});
|
||||
}
|
||||
}
|
||||
std::sort(blend_list.begin(), blend_list.end(),
|
||||
[](const SortableSnapshot& a, const SortableSnapshot& b) {
|
||||
return a.distance > b.distance;
|
||||
});
|
||||
|
||||
for (const auto& item : blend_list) {
|
||||
const auto& snapshot = *item.snapshot;
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_manager.get_texture_array());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, snapshot.normal_blend_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));
|
||||
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex),
|
||||
(void*)offsetof(Vertex, layer));
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, snapshot.normal_blend_vertices_count);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
@@ -966,8 +985,10 @@ void World::update(float delta_time) {
|
||||
m_render_snapshots.push_back(
|
||||
{chunk.get_normal_vbo(), chunk.get_normal_vertices_sum(),
|
||||
chunk.get_cross_vbo(), chunk.get_cross_vertices_sum(),
|
||||
chunk.get_transparent_vbo(),
|
||||
chunk.get_transparent_vertices_sum(),
|
||||
chunk.get_normal_discard_vbo(),
|
||||
chunk.get_normal_discard_vertices_sum(),
|
||||
chunk.get_normal_blend_vbo(),
|
||||
chunk.get_normal_blend_vertices_sum(),
|
||||
glm::vec3(static_cast<float>(pos.x * CHUNK_SIZE) +
|
||||
static_cast<float>(CHUNK_SIZE / 2),
|
||||
static_cast<float>(WORLD_SIZE_Y / 2),
|
||||
|
||||
Reference in New Issue
Block a user