From d0bc8d627fae3582e856c82a422961abae8b0db1 Mon Sep 17 00:00:00 2001 From: zhenyan121 <104683324+zhenyan121@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:21:19 +0800 Subject: [PATCH] refactor: transparent render (#14) * fix(renderer): defer uniform location retrieval and add view matrix in outline rendering * refactor(gameplay): encapsulate per-type vertex data into VertexData struct * feat(rendering): separate transparent blocks into discard and blend modes * feat(renderer): implement order-independent transparency * fix(shaders): reduce alpha discard threshold to 0.8 --- CMakeLists.txt | 1 + assets/data/block/air.toml | 2 + assets/data/block/dirt.toml | 2 + assets/data/block/grass.toml | 2 + assets/data/block/grass_block.toml | 2 + assets/data/block/leaf.toml | 2 + assets/data/block/log.toml | 2 + assets/data/block/sand.toml | 2 + assets/data/block/snowy_grass_block.toml | 2 + assets/data/block/stone.toml | 2 + assets/data/block/template.toml | 2 + assets/data/block/water.toml | 2 + .../shaders/block_accumulation_f_shader.glsl | 28 ++ .../shaders/block_accumulation_v_shader.glsl | 21 ++ assets/shaders/block_composite_f_shader.glsl | 19 ++ assets/shaders/block_composite_v_shader.glsl | 11 + assets/shaders/block_f_shader.glsl | 2 +- include/Cubed/gameplay/block.hpp | 13 +- include/Cubed/gameplay/chunk.hpp | 33 +-- include/Cubed/gameplay/vertex_data.hpp | 24 ++ include/Cubed/gameplay/world.hpp | 14 +- include/Cubed/renderer.hpp | 9 +- include/Cubed/tools/math_tools.hpp | 3 + src/block.cpp | 20 +- src/gameplay/chunk.cpp | 194 ++++++-------- src/gameplay/vertex_data.cpp | 39 +++ src/gameplay/world.cpp | 137 +--------- src/renderer.cpp | 251 +++++++++++++++++- src/tools/math_tools.cpp | 15 ++ 29 files changed, 572 insertions(+), 284 deletions(-) create mode 100644 assets/shaders/block_accumulation_f_shader.glsl create mode 100644 assets/shaders/block_accumulation_v_shader.glsl create mode 100644 assets/shaders/block_composite_f_shader.glsl create mode 100644 assets/shaders/block_composite_v_shader.glsl create mode 100644 include/Cubed/gameplay/vertex_data.hpp create mode 100644 src/gameplay/vertex_data.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9145341..cbfc917 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,7 @@ add_executable(${PROJECT_NAME} src/gameplay/river_worm.cpp src/gameplay/river_path.cpp src/block.cpp + src/gameplay/vertex_data.cpp ) if(CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/assets/data/block/air.toml b/assets/data/block/air.toml index 0a15eea..2b16aa3 100644 --- a/assets/data/block/air.toml +++ b/assets/data/block/air.toml @@ -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 diff --git a/assets/data/block/dirt.toml b/assets/data/block/dirt.toml index 8c1af59..f62f7e3 100644 --- a/assets/data/block/dirt.toml +++ b/assets/data/block/dirt.toml @@ -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 diff --git a/assets/data/block/grass.toml b/assets/data/block/grass.toml index 05a911b..4eccd44 100644 --- a/assets/data/block/grass.toml +++ b/assets/data/block/grass.toml @@ -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 diff --git a/assets/data/block/grass_block.toml b/assets/data/block/grass_block.toml index 266c892..84bdf57 100644 --- a/assets/data/block/grass_block.toml +++ b/assets/data/block/grass_block.toml @@ -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 diff --git a/assets/data/block/leaf.toml b/assets/data/block/leaf.toml index 3fc5943..ef8ba3f 100644 --- a/assets/data/block/leaf.toml +++ b/assets/data/block/leaf.toml @@ -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 diff --git a/assets/data/block/log.toml b/assets/data/block/log.toml index 40eb1a5..1dea710 100644 --- a/assets/data/block/log.toml +++ b/assets/data/block/log.toml @@ -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 diff --git a/assets/data/block/sand.toml b/assets/data/block/sand.toml index 0ec5867..bb23bbc 100644 --- a/assets/data/block/sand.toml +++ b/assets/data/block/sand.toml @@ -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 diff --git a/assets/data/block/snowy_grass_block.toml b/assets/data/block/snowy_grass_block.toml index 94f6e36..f6b501a 100644 --- a/assets/data/block/snowy_grass_block.toml +++ b/assets/data/block/snowy_grass_block.toml @@ -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 diff --git a/assets/data/block/stone.toml b/assets/data/block/stone.toml index df5b889..b5dddd3 100644 --- a/assets/data/block/stone.toml +++ b/assets/data/block/stone.toml @@ -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 diff --git a/assets/data/block/template.toml b/assets/data/block/template.toml index 8f4e951..4832ece 100644 --- a/assets/data/block/template.toml +++ b/assets/data/block/template.toml @@ -5,3 +5,5 @@ is_gas = false is_passable = false is_cross_plane = false is_transparent = false +is_discard = false +is_blend = false diff --git a/assets/data/block/water.toml b/assets/data/block/water.toml index 710ec0a..ed808b6 100644 --- a/assets/data/block/water.toml +++ b/assets/data/block/water.toml @@ -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 diff --git a/assets/shaders/block_accumulation_f_shader.glsl b/assets/shaders/block_accumulation_f_shader.glsl new file mode 100644 index 0000000..6720521 --- /dev/null +++ b/assets/shaders/block_accumulation_f_shader.glsl @@ -0,0 +1,28 @@ +#version 460 + +layout (location = 0) out vec4 accum; +layout (location = 1) out float reveal; + +in vec2 tc; +flat in int tex_layer; +in float v_depth; +layout (binding = 0) uniform sampler2DArray samp; + +float weight(float z, float a) { + float intermediate = 0.03 / (1e-5 + pow(z / 200.0, 4.0)); + + return a * clamp(intermediate, 1e-2, 3e2); +} + +void main() { + vec4 color = texture(samp, vec3(tc, tex_layer)); + float alpha = color.a; + if (alpha < 1e-4) discard; + + + float w = weight(v_depth, alpha); + + accum = vec4(color.rgb * alpha * w, alpha * w); + + reveal = alpha; +} \ No newline at end of file diff --git a/assets/shaders/block_accumulation_v_shader.glsl b/assets/shaders/block_accumulation_v_shader.glsl new file mode 100644 index 0000000..b7a22e5 --- /dev/null +++ b/assets/shaders/block_accumulation_v_shader.glsl @@ -0,0 +1,21 @@ +#version 460 + +layout (location = 0) in vec3 pos; +layout (location = 1) in vec2 texCoord; +layout (location = 2) in float layer; +out vec2 tc; +flat out int tex_layer; +out float v_depth; + +uniform mat4 mv_matrix; +uniform mat4 proj_matrix; + + + +void main(void) { + vec4 view_pos = mv_matrix * vec4(pos, 1.0); + gl_Position = proj_matrix * view_pos; + tc = texCoord; + tex_layer = int(layer); + v_depth = -view_pos.z; +} diff --git a/assets/shaders/block_composite_f_shader.glsl b/assets/shaders/block_composite_f_shader.glsl new file mode 100644 index 0000000..12fb1b9 --- /dev/null +++ b/assets/shaders/block_composite_f_shader.glsl @@ -0,0 +1,19 @@ +#version 460 + +uniform sampler2D u_accumTex; +uniform sampler2D u_revealTex; +in vec2 TexCoord; +out vec4 FragColor; + +void main() { + vec4 a = texture(u_accumTex, TexCoord); + float r = texture(u_revealTex, TexCoord).r; + + if (a.a < 1e-4) discard; + + vec3 color = a.rgb / max(a.a, 1e-5); + float transmittance = r; + float opacity = 1.0 - transmittance; + + FragColor = vec4(color * opacity, opacity); +} diff --git a/assets/shaders/block_composite_v_shader.glsl b/assets/shaders/block_composite_v_shader.glsl new file mode 100644 index 0000000..e0863a8 --- /dev/null +++ b/assets/shaders/block_composite_v_shader.glsl @@ -0,0 +1,11 @@ +#version 460 + +layout (location = 0) in vec2 pos; +layout (location = 1) in vec2 texCoord; + +out vec2 TexCoord; + +void main() { + gl_Position = vec4(pos.x, pos.y, 0.0, 1.0); + TexCoord = texCoord; +} \ No newline at end of file diff --git a/assets/shaders/block_f_shader.glsl b/assets/shaders/block_f_shader.glsl index e9ad2be..2523ed7 100644 --- a/assets/shaders/block_f_shader.glsl +++ b/assets/shaders/block_f_shader.glsl @@ -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.8) { discard; } //color = varyingColor; diff --git a/include/Cubed/gameplay/block.hpp b/include/Cubed/gameplay/block.hpp index b81b90e..c6c6770 100644 --- a/include/Cubed/gameplay/block.hpp +++ b/include/Cubed/gameplay/block.hpp @@ -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: diff --git a/include/Cubed/gameplay/chunk.hpp b/include/Cubed/gameplay/chunk.hpp index 204adcc..7fc4d00 100644 --- a/include/Cubed/gameplay/chunk.hpp +++ b/include/Cubed/gameplay/chunk.hpp @@ -4,7 +4,7 @@ #include "Cubed/gameplay/block.hpp" #include "Cubed/gameplay/chunk_generator.hpp" #include "Cubed/gameplay/chunk_pos.hpp" -#include "Cubed/primitive_data.hpp" +#include "Cubed/gameplay/vertex_data.hpp" #include #include @@ -17,13 +17,10 @@ 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 m_dirty{false}; std::atomic m_need_upload{true}; std::atomic m_is_on_gen_vertex_data{false}; - std::atomic m_normal_vertices_sum = 0; - std::atomic m_cross_vertices_sum = 0; - std::atomic m_transparent_vertices_sum = 0; std::atomic m_biome = BiomeType::PLAIN; std::mutex m_vertexs_data_mutex; @@ -34,12 +31,14 @@ private: HeightMapArray m_heightmap; // the index is a array of block id std::vector m_blocks; - GLuint m_normal_vbo = 0; - GLuint m_cross_plane_vbo = 0; - GLuint m_transparent_normal_vbo = 0; - std::vector m_normal_vertices; - std::vector m_cross_plane_vertices; - std::vector m_transparent_normal_vertices; + + /* + 0 - normal + 1 - cross_plane + 2 - normal_discard + 3 - transparent and blend + */ + std::vector m_vertex_data; float frequency = 0.01f; float height = 80; unsigned m_seed = 0; @@ -47,9 +46,10 @@ private: BiomeConditions m_conditions; void clear_dirty(); - void gen_normal_vertices( + void gen_vertices( const std::array*, 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); @@ -107,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(); diff --git a/include/Cubed/gameplay/vertex_data.hpp b/include/Cubed/gameplay/vertex_data.hpp new file mode 100644 index 0000000..9134197 --- /dev/null +++ b/include/Cubed/gameplay/vertex_data.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "Cubed/primitive_data.hpp" + +#include +#include +#include +namespace Cubed { +class World; +struct VertexData { + std::vector m_vertices; + GLuint m_vbo = 0; + std::atomic m_sum{0}; + World& m_world; + VertexData(World& world); + ~VertexData(); + VertexData(const VertexData&) = delete; + VertexData(VertexData&&) noexcept; + VertexData& operator=(const VertexData&) = delete; + VertexData& operator=(VertexData&&) noexcept; + + void upload(); + void update_sum(); +}; +} // namespace Cubed diff --git a/include/Cubed/gameplay/world.hpp b/include/Cubed/gameplay/world.hpp index b676856..0338285 100644 --- a/include/Cubed/gameplay/world.hpp +++ b/include/Cubed/gameplay/world.hpp @@ -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,9 +92,6 @@ public: Player& get_player(const std::string& name); void init_world(); - bool is_aabb_in_frustum(const glm::vec3& center, - const glm::vec3& half_extents); - int get_block(const glm::ivec3& block_pos) const; bool is_solid(const glm::ivec3& block_pos) const; bool can_pass_block(const glm::ivec3& block_pos) const; @@ -100,9 +99,6 @@ public: static ChunkPos chunk_pos(int world_x, int world_z); void need_gen(); - void render(const glm::mat4& mvp_matrix, - const TextureManager& texture_manager, - const glm::vec3& camera_pos); void set_block(const glm::ivec3& pos, unsigned id); void update(float delta_time); @@ -121,6 +117,8 @@ public: CaveCarver& cave_carcer(); RiverWorm& river_worm(); + std::vector& planes(); + std::vector& render_snapshots(); }; } // namespace Cubed diff --git a/include/Cubed/renderer.hpp b/include/Cubed/renderer.hpp index 7225b71..8e77a72 100644 --- a/include/Cubed/renderer.hpp +++ b/include/Cubed/renderer.hpp @@ -15,7 +15,7 @@ class World; class DevPanel; class Renderer { public: - constexpr static int NUM_VAO = 6; + constexpr static int NUM_VAO = 7; Renderer(const Camera& camera, World& world, const TextureManager& texture_manager, DevPanel& dev_panel); @@ -40,6 +40,9 @@ private: float m_delta_time = 0.0f; + float m_width = 0.0f; + float m_height = 0.0f; + glm::mat4 m_p_mat, m_v_mat, m_m_mat, m_mv_mat, m_mvp_mat; GLuint m_mv_loc = 0; @@ -55,6 +58,10 @@ private: GLuint m_screen_texture = 0; GLuint m_depth_render_buffer = 0; + GLuint m_oit_fbo = 0; + GLuint m_accum_texture = 0; + GLuint m_reveal_texture = 0; + GLuint m_oit_depth_render_buffer = 0; GLuint m_quad_vbo = 0; glm::mat4 m_ui_proj; diff --git a/include/Cubed/tools/math_tools.hpp b/include/Cubed/tools/math_tools.hpp index 61f20d5..4a276b4 100644 --- a/include/Cubed/tools/math_tools.hpp +++ b/include/Cubed/tools/math_tools.hpp @@ -9,6 +9,9 @@ void extract_frustum_planes(const glm::mat4& mvp_matrix, std::vector& planes); float smootherstep(float edge0, float edge1, float x); +bool is_aabb_in_frustum(const glm::vec3& center, const glm::vec3& half_extents, + const std::vector& planes); + } // namespace Math } // namespace Cubed \ No newline at end of file diff --git a/src/block.cpp b/src/block.cpp index 6074a12..ddb3b4a 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -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(), diff --git a/src/gameplay/chunk.cpp b/src/gameplay/chunk.cpp index 6f71f58..7be8e4d 100644 --- a/src/gameplay/chunk.cpp +++ b/src/gameplay/chunk.cpp @@ -9,65 +9,36 @@ namespace Cubed { Chunk::Chunk(World& world, ChunkPos chunk_pos) - : m_chunk_pos(chunk_pos), m_world(world) {} - -Chunk::~Chunk() { - if (m_normal_vbo != 0) { - m_world.push_delete_vbo(m_normal_vbo); - } - if (m_cross_plane_vbo != 0) { - m_world.push_delete_vbo(m_cross_plane_vbo); - } - if (m_transparent_normal_vbo != 0) { - m_world.push_delete_vbo(m_transparent_normal_vbo); + : m_chunk_pos(chunk_pos), m_world(world) { + for (int i = 0; i < VERTEX_DATA_SUM; i++) { + m_vertex_data.emplace_back(m_world); } } +Chunk::~Chunk() {} + Chunk::Chunk(Chunk&& other) noexcept : m_dirty(other.is_dirty()), m_need_upload(other.m_need_upload.load()), m_is_on_gen_vertex_data(other.m_is_on_gen_vertex_data.load()), - m_normal_vertices_sum(other.m_normal_vertices_sum.load()), - m_cross_vertices_sum(other.m_cross_vertices_sum.load()), - m_transparent_vertices_sum(other.m_transparent_vertices_sum.load()), m_biome(other.m_biome.load()), m_chunk_pos(std::move(other.m_chunk_pos)), m_world(other.m_world), m_heightmap(std::move(other.m_heightmap)), - m_blocks(std::move(other.m_blocks)), m_normal_vbo(other.m_normal_vbo), - m_cross_plane_vbo(other.m_cross_plane_vbo), - m_transparent_normal_vbo(other.m_transparent_normal_vbo), - m_normal_vertices(std::move(other.m_normal_vertices)), - m_cross_plane_vertices(std::move(other.m_cross_plane_vertices)), - m_transparent_normal_vertices( - std::move(other.m_transparent_normal_vertices)), - m_seed(other.m_seed), m_conditions(other.m_conditions) { - other.m_normal_vbo = 0; - other.m_cross_plane_vbo = 0; - other.m_transparent_normal_vbo = 0; -} + m_blocks(std::move(other.m_blocks)), + m_vertex_data(std::move(other.m_vertex_data)), m_seed(other.m_seed), + m_conditions(other.m_conditions) {} Chunk& Chunk::operator=(Chunk&& other) noexcept { // Logger::info("other Chunk pos {} {} in Chunk& Chunk::operator=(Chunk&& // other) this {}", other.m_chunk_pos.x, other.m_chunk_pos.z, // static_cast(&other)); - m_normal_vbo = other.m_normal_vbo; - other.m_normal_vbo = 0; - m_cross_plane_vbo = other.m_cross_plane_vbo; - m_transparent_normal_vbo = other.m_transparent_normal_vbo; - other.m_transparent_normal_vbo = 0; - other.m_cross_plane_vbo = 0; + m_chunk_pos = std::move(other.m_chunk_pos); m_heightmap = std::move(other.m_heightmap); m_blocks = std::move(other.m_blocks); m_dirty = other.is_dirty(); - m_normal_vertices = std::move(other.m_normal_vertices); - m_cross_plane_vertices = std::move(other.m_cross_plane_vertices); - m_transparent_normal_vertices = - std::move(other.m_transparent_normal_vertices); + m_vertex_data = std::move(other.m_vertex_data); m_biome = other.m_biome.load(); m_is_on_gen_vertex_data = other.m_is_on_gen_vertex_data.load(); m_need_upload = other.m_need_upload.load(); - m_normal_vertices_sum = other.m_normal_vertices_sum.load(); - m_cross_vertices_sum = other.m_cross_vertices_sum.load(); - m_transparent_vertices_sum = other.m_transparent_vertices_sum.load(); m_seed = other.m_seed; m_conditions = other.m_conditions; return *this; @@ -139,29 +110,41 @@ void Chunk::gen_vertex_data( } m_is_on_gen_vertex_data = true; std::lock_guard lk(m_vertexs_data_mutex); - gen_normal_vertices(neighbor_block); - gen_cross_plane_vertices(); + + for (auto& data : m_vertex_data) { + data.m_vertices.clear(); + } + + gen_vertices(neighbor_block); + for (auto& data : m_vertex_data) { + data.update_sum(); + } m_need_upload = true; m_is_on_gen_vertex_data = false; } -GLuint Chunk::get_normal_vbo() const { return m_normal_vbo; } +GLuint Chunk::get_normal_vbo() const { return m_vertex_data[0].m_vbo; } size_t Chunk::get_normal_vertices_sum() const { - if (m_normal_vertices_sum == 0) { + if (m_vertex_data[0].m_sum == 0) { Logger::warn("m_normal_vertices_sum is 0"); } - return m_normal_vertices_sum.load(); + return m_vertex_data[0].m_sum.load(); } -GLuint Chunk::get_cross_vbo() const { return m_cross_plane_vbo; } +GLuint Chunk::get_cross_vbo() const { return m_vertex_data[1].m_vbo; } size_t Chunk::get_cross_vertices_sum() const { - return m_cross_vertices_sum.load(); + return m_vertex_data[1].m_sum.load(); } -GLuint Chunk::get_transparent_vbo() const { return m_transparent_normal_vbo; } -size_t Chunk::get_transparent_vertices_sum() const { - return m_transparent_vertices_sum.load(); +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() { @@ -235,33 +218,12 @@ void Chunk::upload_to_gpu() { ASSERT(is_need_upload()); - if (m_normal_vbo == 0) { - glGenBuffers(1, &m_normal_vbo); + std::lock_guard lk(m_vertexs_data_mutex); + + for (auto& data : m_vertex_data) { + data.upload(); } - std::lock_guard lk(m_vertexs_data_mutex); - glBindBuffer(GL_ARRAY_BUFFER, m_normal_vbo); - glBufferData(GL_ARRAY_BUFFER, m_normal_vertices.size() * sizeof(Vertex), - m_normal_vertices.data(), GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - if (m_cross_plane_vertices.size() != 0) { - if (m_cross_plane_vbo == 0) { - glGenBuffers(1, &m_cross_plane_vbo); - } - glBindBuffer(GL_ARRAY_BUFFER, m_cross_plane_vbo); - glBufferData(GL_ARRAY_BUFFER, - m_cross_plane_vertices.size() * sizeof(Vertex), - m_cross_plane_vertices.data(), GL_DYNAMIC_DRAW); - } - if (m_transparent_normal_vertices.size() != 0) { - if (m_transparent_normal_vbo == 0) { - glGenBuffers(1, &m_transparent_normal_vbo); - } - glBindBuffer(GL_ARRAY_BUFFER, m_transparent_normal_vbo); - glBufferData(GL_ARRAY_BUFFER, - m_transparent_normal_vertices.size() * sizeof(Vertex), - m_transparent_normal_vertices.data(), GL_DYNAMIC_DRAW); - } // after fininshed it, can use clear_dirty(); m_need_upload = false; @@ -300,10 +262,8 @@ unsigned Chunk::seed() const { BiomeConditions& Chunk::conditions() { return m_conditions; } -void Chunk::gen_normal_vertices( +void Chunk::gen_vertices( const std::array*, 4>& neighbor_block) { - m_normal_vertices.clear(); - m_transparent_normal_vertices.clear(); static const glm::ivec3 DIR[6] = {{0, 0, 1}, {1, 0, 0}, {0, 0, -1}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}}; @@ -399,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, @@ -410,55 +374,57 @@ void Chunk::gen_normal_vertices( }; if (BlockManager::is_transparent(cur_id)) { - m_transparent_normal_vertices.emplace_back(vex); + if (BlockManager::is_discard(cur_id) && + BlockManager::is_blend(cur_id)) { + Logger::warn( + "Block id {} is both discard and blend is " + "must only one can true !!!", + 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_normal_vertices.emplace_back(vex); + m_vertex_data[0].m_vertices.emplace_back(vex); } } } } } } - m_normal_vertices_sum = m_normal_vertices.size(); - m_transparent_vertices_sum = m_transparent_normal_vertices.size(); } -void Chunk::gen_cross_plane_vertices() { +void Chunk::gen_cross_plane_vertices(int world_x, int world_y, int world_z, + BlockType id) { - m_cross_plane_vertices.clear(); + if (!BlockManager::is_cross_plane(id)) { + 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, + CROSS_TEX_COORDS[face][i][0], + CROSS_TEX_COORDS[face][i][1], + static_cast(BlockManager::cross_plane_index(id)) - 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)]; - - if (!BlockManager::is_cross_plane(id)) { - continue; - } - 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, - CROSS_TEX_COORDS[face][i][0], - CROSS_TEX_COORDS[face][i][1], - static_cast( - BlockManager::cross_plane_index(id)) - - }; - m_cross_plane_vertices.emplace_back(vex); - } - } - } + }; + m_vertex_data[1].m_vertices.emplace_back(vex); } } - m_cross_vertices_sum = m_cross_plane_vertices.size(); - // Logger::info("Cross Sum {}", m_cross_vertices_sum.load()); } +// Logger::info("Cross Sum {}", m_cross_vertices_sum.load()); + } // namespace Cubed diff --git a/src/gameplay/vertex_data.cpp b/src/gameplay/vertex_data.cpp new file mode 100644 index 0000000..fd796eb --- /dev/null +++ b/src/gameplay/vertex_data.cpp @@ -0,0 +1,39 @@ +#include "Cubed/gameplay/vertex_data.hpp" + +#include "Cubed/gameplay/world.hpp" + +namespace Cubed { +VertexData::VertexData(World& world) : m_world(world) {} +VertexData::~VertexData() { + if (m_vbo != 0) { + m_world.push_delete_vbo(m_vbo); + } +} +VertexData::VertexData(VertexData&& o) noexcept + : m_vertices(std::move(o.m_vertices)), m_vbo(o.m_vbo), + m_sum(o.m_sum.load()), m_world(o.m_world) { + o.m_vbo = 0; + o.m_sum = 0; +} +VertexData& VertexData::operator=(VertexData&& o) noexcept { + m_vbo = o.m_vbo; + o.m_vbo = 0; + m_sum = o.m_sum.load(); + o.m_sum = 0; + m_vertices = std::move(o.m_vertices); + return *this; +} +void VertexData::upload() { + if (m_vertices.size() == 0) { + return; + } + if (m_vbo == 0) { + glGenBuffers(1, &m_vbo); + } + glBindBuffer(GL_ARRAY_BUFFER, m_vbo); + glBufferData(GL_ARRAY_BUFFER, m_vertices.size() * sizeof(Vertex), + m_vertices.data(), GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} +void VertexData::update_sum() { m_sum = m_vertices.size(); } +} // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/world.cpp b/src/gameplay/world.cpp index 6c7e8e6..3c1673d 100644 --- a/src/gameplay/world.cpp +++ b/src/gameplay/world.cpp @@ -1,12 +1,9 @@ #include "Cubed/gameplay/world.hpp" #include "Cubed/config.hpp" -#include "Cubed/debug_collector.hpp" #include "Cubed/gameplay/player.hpp" -#include "Cubed/texture_manager.hpp" #include "Cubed/tools/cubed_assert.hpp" #include "Cubed/tools/cubed_hash.hpp" -#include "Cubed/tools/math_tools.hpp" namespace Cubed { @@ -291,115 +288,6 @@ void World::init_chunks() { } } */ -void World::render(const glm::mat4& mvp_matrix, - const TextureManager& texture_manager, - const glm::vec3& camera_pos) { - Math::extract_frustum_planes(mvp_matrix, m_planes); - int rendered_sum = 0; - for (const auto& snapshot : m_render_snapshots) { - - if (is_aabb_in_frustum(snapshot.center, snapshot.half_extents)) { - glBindTexture(GL_TEXTURE_2D_ARRAY, - texture_manager.get_texture_array()); - glBindBuffer(GL_ARRAY_BUFFER, snapshot.normal_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_vertices_count); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - rendered_sum++; - } - } - glDepthMask(GL_FALSE); - - struct SortableSnapshot { - const ChunkRenderSnapshot* snapshot; - float distance; - }; - - std::vector cross_list; - std::vector transparent_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); - 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); - 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.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); - 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.transparent_vertices_count); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - glDepthMask(GL_TRUE); - DebugCollector::get().report( - "rendered_chunk", "Rendered Chunk: " + std::to_string(rendered_sum)); -} ChunkPos World::chunk_pos(int world_x, int world_z) { int chunk_x, chunk_z; @@ -774,21 +662,6 @@ void World::need_gen() { m_gen_cv.notify_one(); } -bool World::is_aabb_in_frustum(const glm::vec3& center, - const glm::vec3& half_extents) { - for (const auto& plane : m_planes) { - // distance - float d = glm::dot(glm::vec3(plane), center) + plane.w; - float r = half_extents.x * std::abs(plane.x) + - half_extents.y * std::abs(plane.y) + - half_extents.z * std::abs(plane.z); - if (d + r < 0) { - return false; - } - } - return true; -} - int World::get_block(const glm::ivec3& block_pos) const { auto [chunk_x, chunk_z] = chunk_pos(block_pos.x, block_pos.z); std::lock_guard lk(m_chunks_mutex); @@ -966,8 +839,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(pos.x * CHUNK_SIZE) + static_cast(CHUNK_SIZE / 2), static_cast(WORLD_SIZE_Y / 2), @@ -1024,4 +899,8 @@ void World::rendering_distance(int rendering_distance) { CaveCarver& World::cave_carcer() { return m_cave_carcer; } RiverWorm& World::river_worm() { return m_river_worm; } +std::vector& World::planes() { return m_planes; } +std::vector& World::render_snapshots() { + return m_render_snapshots; +}; } // namespace Cubed \ No newline at end of file diff --git a/src/renderer.cpp b/src/renderer.cpp index ac6c7cd..2d3deb3 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -12,6 +12,7 @@ #include "Cubed/tools/cubed_hash.hpp" #include "Cubed/tools/font.hpp" #include "Cubed/tools/log.hpp" +#include "Cubed/tools/math_tools.hpp" #include "Cubed/tools/shader_tools.hpp" #include @@ -36,6 +37,11 @@ Renderer::~Renderer() { glDeleteFramebuffers(1, &m_fbo); glDeleteTextures(1, &m_screen_texture); glDeleteRenderbuffers(1, &m_depth_render_buffer); + + glDeleteFramebuffers(1, &m_oit_fbo); + glDeleteTextures(1, &m_accum_texture); + glDeleteTextures(1, &m_reveal_texture); + glDeleteRenderbuffers(1, &m_oit_depth_render_buffer); } void Renderer::hot_reload() { @@ -52,7 +58,7 @@ void Renderer::init() { Logger::info("Renderer: {}", reinterpret_cast(glGetString(GL_RENDERER))); - Shader world_shader{"world", "shaders/block_v_shader.glsl", + Shader world_shader{"normal_block", "shaders/block_v_shader.glsl", "shaders/block_f_shader.glsl"}; Shader outline_shader{"outline", "shaders/outline_v_shader.glsl", "shaders/outline_f_shader.glsl"}; @@ -65,7 +71,11 @@ void Renderer::init() { Shader under_water_shader{"under_water", "shaders/under_water_v_shader.glsl", "shaders/under_water_f_shader.glsl"}; - + Shader accum_shader{"accum", "shaders/block_accumulation_v_shader.glsl", + "shaders/block_accumulation_f_shader.glsl"}; + Shader composite_block_shader{"composite", + "shaders/block_composite_v_shader.glsl", + "shaders/block_composite_f_shader.glsl"}; m_shaders.insert({world_shader.hash(), std::move(world_shader)}); m_shaders.insert({outline_shader.hash(), std::move(outline_shader)}); m_shaders.insert({sky_shdaer.hash(), std::move(sky_shdaer)}); @@ -73,7 +83,9 @@ void Renderer::init() { m_shaders.insert({text_shdaer.hash(), std::move(text_shdaer)}); m_shaders.insert( {under_water_shader.hash(), std::move(under_water_shader)}); - + m_shaders.insert({accum_shader.hash(), std::move(accum_shader)}); + m_shaders.insert( + {composite_block_shader.hash(), std::move(composite_block_shader)}); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); @@ -182,15 +194,19 @@ void Renderer::render_outline() { const auto& shader = get_shader("outline"); shader.use(); - m_mv_loc = shader.loc("mv_matrix"); - m_proj_loc = shader.loc("proj_matrix"); - const auto& block_pos = m_world.get_look_block_pos("TestPlayer"); if (block_pos != std::nullopt) { + + m_mv_loc = shader.loc("mv_matrix"); + m_proj_loc = shader.loc("proj_matrix"); + m_m_mat = glm::translate(glm::mat4(1.0f), glm::vec3(block_pos.value().pos)); + + m_v_mat = m_camera.get_camera_lookat(); m_mv_mat = m_v_mat * m_m_mat; + glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_mv_mat)); glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_p_mat)); @@ -235,7 +251,8 @@ void Renderer::render_sky() { void Renderer::render_text() { const auto& shader = get_shader("text"); shader.use(); - + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_DEPTH_TEST); m_proj_loc = shader.loc("projection"); @@ -254,7 +271,8 @@ void Renderer::render_ui() { shader.use(); glDisable(GL_DEPTH_TEST); - + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); m_mv_loc = shader.loc("m_matrix"); m_proj_loc = shader.loc("proj_matrix"); @@ -330,6 +348,9 @@ void Renderer::updata_framebuffer(int width, int height) { if (m_fbo == 0) { glGenFramebuffers(1, &m_fbo); } + if (m_oit_fbo == 0) { + glGenFramebuffers(1, &m_oit_fbo); + } glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); glDeleteTextures(1, &m_screen_texture); @@ -357,14 +378,51 @@ void Renderer::updata_framebuffer(int width, int height) { Logger::info("Frame Buffer Complete!"); } glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, m_oit_fbo); + glDeleteTextures(1, &m_accum_texture); + glDeleteTextures(1, &m_reveal_texture); + glDeleteRenderbuffers(1, &m_oit_depth_render_buffer); + glGenTextures(1, &m_accum_texture); + glBindTexture(GL_TEXTURE_2D, m_accum_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, + GL_HALF_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + m_accum_texture, 0); + glGenTextures(1, &m_reveal_texture); + glBindTexture(GL_TEXTURE_2D, m_reveal_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, width, height, 0, GL_RED, + GL_HALF_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, + m_reveal_texture, 0); + glGenRenderbuffers(1, &m_oit_depth_render_buffer); + glBindRenderbuffer(GL_RENDERBUFFER, m_oit_depth_render_buffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, m_oit_depth_render_buffer); + GLenum draw_buffer[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; + glDrawBuffers(2, draw_buffer); + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + Logger::error("FBO incomplete after resize!"); + } else { + Logger::info("Frame Buffer Complete!"); + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + m_width = width; + m_height = height; } void Renderer::render_world() { - const auto& shader = get_shader("world"); - shader.use(); + const auto& normal_block_shader = get_shader("normal_block"); + normal_block_shader.use(); - m_mv_loc = shader.loc("mv_matrix"); - m_proj_loc = shader.loc("proj_matrix"); + m_mv_loc = normal_block_shader.loc("mv_matrix"); + m_proj_loc = normal_block_shader.loc("proj_matrix"); glActiveTexture(GL_TEXTURE0); m_m_mat = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f)); @@ -373,7 +431,174 @@ void Renderer::render_world() { glUniformMatrix4fv(m_mv_loc, 1, GL_FALSE, glm::value_ptr(m_mv_mat)); glUniformMatrix4fv(m_proj_loc, 1, GL_FALSE, glm::value_ptr(m_p_mat)); m_mvp_mat = m_p_mat * m_mv_mat; - m_world.render(m_mvp_mat, m_texture_manager, m_camera.get_camera_pos()); + + auto& camera_pos = m_camera.get_camera_pos(); + auto& m_planes = m_world.planes(); + auto& m_render_snapshots = m_world.render_snapshots(); + + Math::extract_frustum_planes(m_mvp_mat, m_planes); + + int rendered_sum = 0; + + for (const auto& snapshot : m_render_snapshots) { + + if (Math::is_aabb_in_frustum(snapshot.center, snapshot.half_extents, + m_planes)) { + glBindTexture(GL_TEXTURE_2D_ARRAY, + m_texture_manager.get_texture_array()); + glBindBuffer(GL_ARRAY_BUFFER, snapshot.normal_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_vertices_count); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + rendered_sum++; + } + } + // cross_plane and discard + + for (const auto& snapshot : m_render_snapshots) { + if (!Math::is_aabb_in_frustum(snapshot.center, snapshot.half_extents, + m_planes)) { + continue; + } + 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) { + glBindTexture(GL_TEXTURE_2D_ARRAY, + m_texture_manager.get_cross_plane_array()); + glBindBuffer(GL_ARRAY_BUFFER, snapshot.cross_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.cross_vertices_count); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + } + if (snapshot.normal_discard_vertices_count != 0) { + glBindTexture(GL_TEXTURE_2D_ARRAY, + m_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), + (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_discard_vertices_count); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + } + + // copy depth buffer + + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_oit_fbo); + glBlitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, + GL_DEPTH_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_oit_fbo); + + // pass one accumulate + auto& accum_shader = get_shader("accum"); + accum_shader.use(); + GLint mv_loc = accum_shader.loc("mv_matrix"); + GLint proj_loc = accum_shader.loc("proj_matrix"); + glUniformMatrix4fv(mv_loc, 1, GL_FALSE, glm::value_ptr(m_mv_mat)); + glUniformMatrix4fv(proj_loc, 1, GL_FALSE, glm::value_ptr(m_p_mat)); + glBindFramebuffer(GL_FRAMEBUFFER, m_oit_fbo); + glClearBufferfv(GL_COLOR, 0, glm::value_ptr(glm::vec4(0.0f))); + float one = 1.0f; + glClearBufferfv(GL_COLOR, 1, &one); + + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + glEnable(GL_BLEND); + glBlendFunci(0, GL_ONE, GL_ONE); + + glBlendFunci(1, GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + for (const auto& snapshot : m_render_snapshots) { + if (!Math::is_aabb_in_frustum(snapshot.center, snapshot.half_extents, + m_planes)) { + continue; + } + + if (snapshot.normal_blend_vertices_count != 0) { + glBindTexture(GL_TEXTURE_2D_ARRAY, + m_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); + } + } + auto& composite_shader = get_shader("composite"); + glDisable(GL_BLEND); + composite_shader.use(); + glUniform1i(composite_shader.loc("u_accumTex"), 0); + glUniform1i(composite_shader.loc("u_revealTex"), 1); + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + glBindVertexArray(m_vao[6]); + + glBindBuffer(GL_ARRAY_BUFFER, m_quad_vbo); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), + (void*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), + (void*)(2 * sizeof(float))); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_accum_texture); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_reveal_texture); + + glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); + + DebugCollector::get().report( + "rendered_chunk", "Rendered Chunk: " + std::to_string(rendered_sum)); } void Renderer::render_dev_panel() { diff --git a/src/tools/math_tools.cpp b/src/tools/math_tools.cpp index 2533c44..c69803e 100644 --- a/src/tools/math_tools.cpp +++ b/src/tools/math_tools.cpp @@ -45,6 +45,21 @@ float smootherstep(float edge0, float edge1, float x) { return x * x * x * (x * (6.0f * x - 15.0f) + 10.0f); } +bool is_aabb_in_frustum(const glm::vec3& center, const glm::vec3& half_extents, + const std::vector& planes) { + for (const auto& plane : planes) { + // distance + float d = glm::dot(glm::vec3(plane), center) + plane.w; + float r = half_extents.x * std::abs(plane.x) + + half_extents.y * std::abs(plane.y) + + half_extents.z * std::abs(plane.z); + if (d + r < 0) { + return false; + } + } + return true; +} + } // namespace Math } // namespace Cubed \ No newline at end of file