From d5a12869e62b66afd097cad9c0dd96b91ac51282 Mon Sep 17 00:00:00 2001 From: zhenyan121 <104683324+zhenyan121@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:27:17 +0800 Subject: [PATCH] feat: include for glsl (#24) * refactor(gameplay): remove unused includes and members, clear vertex data after upload * feat(shader-tools): add recursive #include support for shader sources * refactor(shaders): extract noise and sky color functions into shared GLSL includes --- assets/shaders/compute_sky_color.glsl | 46 +++++++++++++++ assets/shaders/noise.glsl | 25 ++++++++ assets/shaders/sky_f_shader.glsl | 74 +---------------------- assets/shaders/under_water_f_shader.glsl | 28 +-------- assets/shaders/water_f_shader.glsl | 73 +---------------------- include/Cubed/gameplay/cave_path.hpp | 3 - include/Cubed/gameplay/river.path.hpp | 5 -- include/Cubed/gameplay/river_worm.hpp | 2 - src/gameplay/river_worm.cpp | 6 +- src/gameplay/vertex_data.cpp | 3 + src/tools/shader_tools.cpp | 75 ++++++++++++++++++++---- 11 files changed, 142 insertions(+), 198 deletions(-) create mode 100644 assets/shaders/compute_sky_color.glsl create mode 100644 assets/shaders/noise.glsl diff --git a/assets/shaders/compute_sky_color.glsl b/assets/shaders/compute_sky_color.glsl new file mode 100644 index 0000000..3bb34cd --- /dev/null +++ b/assets/shaders/compute_sky_color.glsl @@ -0,0 +1,46 @@ +#include "noise.glsl" + +vec3 computeSkyColor(vec3 dir) { + vec3 sund = normalize(sunDir); + + float t = + clamp( + dir.y * 0.5 + 0.5, + 0.0, + 1.0 + ); + + + vec3 sky = + mix( + skyBottom, + skyTop, + pow(t, horizonSharpness) + ); + + // cloud + if (dir.y > 0.0) { + vec2 cloud_uv = dir.xz / (dir.y + 0.15) * 0.5 + vec2(time * 0.005, time * 0.002); + float cloud_density = fbm(cloud_uv * 2.0); + float safeLow = cloudThresholdLow; + float safeHigh = max(cloudThresholdHigh, cloudThresholdLow + 0.001); + cloud_density = smoothstep(safeLow,safeHigh, cloud_density); + + + float fade = smoothstep(0.0, 0.3, dir.y) * (1.0 - smoothstep(0.85, 1.0, dir.y)); + cloud_density *= fade; + + vec3 cloud_color = mix(skyBottom, vec3(1.0), cloudWhiteMix); + sky = mix(sky, cloud_color, cloud_density * 0.6); + } + + float sunAmount = max(dot(dir, sund), 0.0); + + //float glow = pow(sunAmount, 8.0) * 0.15; + + float glow = pow(sunAmount, 8.0) * 0.15 + pow(sunAmount, 32.0) * 0.3; + + sky += glow * sunColor; + + return sky; +} \ No newline at end of file diff --git a/assets/shaders/noise.glsl b/assets/shaders/noise.glsl new file mode 100644 index 0000000..61071d2 --- /dev/null +++ b/assets/shaders/noise.glsl @@ -0,0 +1,25 @@ +float hash(vec2 p) { + return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123); +} + +float noise(vec2 p) { + vec2 i = floor(p); + vec2 f = fract(p); + f = f * f * (3.0 - 2.0 * f); + float a = hash(i); + float b = hash(i + vec2(1.0, 0.0)); + float c = hash(i + vec2(0.0, 1.0)); + float d = hash(i + vec2(1.0, 1.0)); + return mix(mix(a, b, f.x), mix(c, d, f.x), f.y); +} + +float fbm(vec2 p) { + float v = 0.0; + float amp = 0.5; + for (int i = 0; i < 5; i++) { + v += amp * noise(p); + p *= 2.0; + amp *= 0.5; + } + return v; +} \ No newline at end of file diff --git a/assets/shaders/sky_f_shader.glsl b/assets/shaders/sky_f_shader.glsl index e5672b0..757bb18 100644 --- a/assets/shaders/sky_f_shader.glsl +++ b/assets/shaders/sky_f_shader.glsl @@ -19,84 +19,12 @@ uniform float cloudThresholdHigh; uniform float time; - -float hash(vec2 p) { - return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123); -} - -float noise(vec2 p) { - vec2 i = floor(p); - vec2 f = fract(p); - f = f * f * (3.0 - 2.0 * f); - float a = hash(i); - float b = hash(i + vec2(1.0, 0.0)); - float c = hash(i + vec2(0.0, 1.0)); - float d = hash(i + vec2(1.0, 1.0)); - return mix(mix(a, b, f.x), mix(c, d, f.x), f.y); -} - -float fbm(vec2 p) { - float v = 0.0; - float amp = 0.5; - for (int i = 0; i < 5; i++) { - v += amp * noise(p); - p *= 2.0; - amp *= 0.5; - } - return v; -} - -vec3 computeSkyColor(vec3 dir) { - vec3 sund = normalize(sunDir); - - float t = - clamp( - dir.y * 0.5 + 0.5, - 0.0, - 1.0 - ); - - - vec3 sky = - mix( - skyBottom, - skyTop, - pow(t, horizonSharpness) - ); - - // cloud - if (dir.y > 0.0) { - vec2 cloud_uv = dir.xz / (dir.y + 0.15) * 0.5 + vec2(time * 0.005, time * 0.002); - float cloud_density = fbm(cloud_uv * 2.0); - float safeLow = cloudThresholdLow; - float safeHigh = max(cloudThresholdHigh, cloudThresholdLow + 0.001); - cloud_density = smoothstep(safeLow,safeHigh, cloud_density); - - - float fade = smoothstep(0.0, 0.3, dir.y) * (1.0 - smoothstep(0.85, 1.0, dir.y)); - cloud_density *= fade; - - vec3 cloud_color = mix(skyBottom, vec3(1.0), cloudWhiteMix); - sky = mix(sky, cloud_color, cloud_density * 0.6); - } - - float sunAmount = max(dot(dir, sund), 0.0); - - //float glow = pow(sunAmount, 8.0) * 0.15; - - float glow = pow(sunAmount, 8.0) * 0.15 + pow(sunAmount, 32.0) * 0.3; - - sky += glow * sunColor; - - return sky; -} +#include "compute_sky_color.glsl" void main(void) { vec3 sky = computeSkyColor(dir); frag_color = vec4(sky, 1.0); - //frag_color = vec4(vec3(sunAmount), 1.0); - //frag_color = vec4(t,0,0,1); } \ No newline at end of file diff --git a/assets/shaders/under_water_f_shader.glsl b/assets/shaders/under_water_f_shader.glsl index 390064c..2392b9d 100644 --- a/assets/shaders/under_water_f_shader.glsl +++ b/assets/shaders/under_water_f_shader.glsl @@ -19,33 +19,7 @@ uniform vec3 sunDir; uniform vec3 sunColor; uniform float waterDensity; -float hash(vec2 p) { - return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); -} - -float noise(vec2 p) { - vec2 i = floor(p); - vec2 f = fract(p); - f = f * f * (3.0 - 2.0 * f); - - return mix( - mix(hash(i), hash(i + vec2(1.0, 0.0)), f.x), - mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), f.x), - f.y - ); -} - -float fbm(vec2 p) { - float value = 0.0; - float amp = 0.5; - float freq = 1.0; - for (int i = 0; i < 4; ++i) { - value += amp * noise(p * freq); - freq *= 2.0; - amp *= 0.5; - } - return value; -} +#include "noise.glsl" float getCausticValue(float x, float y, float z) { float w = 8.0; diff --git a/assets/shaders/water_f_shader.glsl b/assets/shaders/water_f_shader.glsl index 7b3f52d..6875862 100644 --- a/assets/shaders/water_f_shader.glsl +++ b/assets/shaders/water_f_shader.glsl @@ -42,82 +42,15 @@ uniform float refractStrength; uniform bool enablePerturb; uniform bool enableDepthFade; + +#include "compute_sky_color.glsl" + 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); } -float hash(vec2 p) { - return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123); -} - -float noise(vec2 p) { - vec2 i = floor(p); - vec2 f = fract(p); - f = f * f * (3.0 - 2.0 * f); - float a = hash(i); - float b = hash(i + vec2(1.0, 0.0)); - float c = hash(i + vec2(0.0, 1.0)); - float d = hash(i + vec2(1.0, 1.0)); - return mix(mix(a, b, f.x), mix(c, d, f.x), f.y); -} - -float fbm(vec2 p) { - float v = 0.0; - float amp = 0.5; - for (int i = 0; i < 5; i++) { - v += amp * noise(p); - p *= 2.0; - amp *= 0.5; - } - return v; -} - -vec3 computeSkyColor(vec3 dir) { - vec3 sund = normalize(sunDir); - - float t = - clamp( - dir.y * 0.5 + 0.5, - 0.0, - 1.0 - ); - - - vec3 sky = - mix( - skyBottom, - skyTop, - pow(t, horizonSharpness) - ); - - // cloud - if (dir.y > 0.0) { - vec2 cloud_uv = dir.xz / (dir.y + 0.15) * 0.5 + vec2(time * 0.005, time * 0.002); - float cloud_density = fbm(cloud_uv * 2.0); - float safeLow = cloudThresholdLow; - float safeHigh = max(cloudThresholdHigh, cloudThresholdLow + 0.001); - cloud_density = smoothstep(safeLow,safeHigh, cloud_density); - - - float fade = smoothstep(0.0, 0.3, dir.y) * (1.0 - smoothstep(0.85, 1.0, dir.y)); - cloud_density *= fade; - - vec3 cloud_color = mix(skyBottom, vec3(1.0), cloudWhiteMix); - sky = mix(sky, cloud_color, cloud_density * 0.6); - } - - float sunAmount = max(dot(dir, sund), 0.0); - - //float glow = pow(sunAmount, 8.0) * 0.15; - - float glow = pow(sunAmount, 8.0) * 0.15 + pow(sunAmount, 32.0) * 0.3; - - sky += glow * sunColor; - - return sky; -} // Reconstruct eye-space coordinates from screen UV and depth buffer value vec3 reconstructViewPos(vec2 uv, float depth) { diff --git a/include/Cubed/gameplay/cave_path.hpp b/include/Cubed/gameplay/cave_path.hpp index 36d95a5..6a8ea5b 100644 --- a/include/Cubed/gameplay/cave_path.hpp +++ b/include/Cubed/gameplay/cave_path.hpp @@ -1,6 +1,5 @@ #pragma once -#include "Cubed/gameplay/chunk_pos.hpp" #include "Cubed/gameplay/path_point.hpp" #include "Cubed/tools/cubed_random.hpp" @@ -9,8 +8,6 @@ namespace Cubed { class CavePath { - using ChunkPosSet = - tbb::concurrent_hash_map; public: CavePath(unsigned int chunk_seed, unsigned world_seed, diff --git a/include/Cubed/gameplay/river.path.hpp b/include/Cubed/gameplay/river.path.hpp index 8e44c15..31e8266 100644 --- a/include/Cubed/gameplay/river.path.hpp +++ b/include/Cubed/gameplay/river.path.hpp @@ -1,6 +1,5 @@ #pragma once -#include "Cubed/gameplay/chunk_pos.hpp" #include "Cubed/gameplay/path_point.hpp" #include "Cubed/tools/cubed_random.hpp" @@ -9,8 +8,6 @@ namespace Cubed { class RiverPath { - using ChunkPosSet = - tbb::concurrent_hash_map; public: RiverPath(unsigned int chunk_seed, unsigned world_seed, @@ -46,8 +43,6 @@ private: Random m_random; std::vector m_points; - ChunkPosSet m_pending_chunks; void collect_path_points(); - void precompute_chunk_coverage(); }; } // namespace Cubed diff --git a/include/Cubed/gameplay/river_worm.hpp b/include/Cubed/gameplay/river_worm.hpp index 44535aa..03f894e 100644 --- a/include/Cubed/gameplay/river_worm.hpp +++ b/include/Cubed/gameplay/river_worm.hpp @@ -1,7 +1,6 @@ #pragma once #include "Cubed/gameplay/chunk_pos.hpp" #include "Cubed/gameplay/path.hpp" -#include "Cubed/tools/cubed_random.hpp" #include #include @@ -25,7 +24,6 @@ public: private: std::atomic m_world_seed{0}; - Random m_random; std::atomic m_probability{0.01f}; }; diff --git a/src/gameplay/river_worm.cpp b/src/gameplay/river_worm.cpp index 5a1010a..f5959ca 100644 --- a/src/gameplay/river_worm.cpp +++ b/src/gameplay/river_worm.cpp @@ -7,11 +7,7 @@ namespace Cubed { RiverWorm::RiverWorm() {} RiverWorm::~RiverWorm() {} -void RiverWorm::init(unsigned world_seed) { - m_world_seed = world_seed; - - m_random.init(m_world_seed); -} +void RiverWorm::init(unsigned world_seed) { m_world_seed = world_seed; } void RiverWorm::reload(unsigned world_seed) { diff --git a/src/gameplay/vertex_data.cpp b/src/gameplay/vertex_data.cpp index 03df63a..3b3421e 100644 --- a/src/gameplay/vertex_data.cpp +++ b/src/gameplay/vertex_data.cpp @@ -63,6 +63,9 @@ void VertexData::upload() { glEnableVertexAttribArray(5); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); + + // Release memory + m_vertices.clear(); } void VertexData::update_sum() { m_sum = m_vertices.size(); } } // namespace Cubed \ No newline at end of file diff --git a/src/tools/shader_tools.cpp b/src/tools/shader_tools.cpp index d5873d7..9774d86 100644 --- a/src/tools/shader_tools.cpp +++ b/src/tools/shader_tools.cpp @@ -5,11 +5,70 @@ #include #include +#include namespace Cubed { namespace fs = std::filesystem; +namespace { + +bool is_include(const std::string& line) { + + std::string_view sv(line); + + auto first = sv.find_first_not_of(" \t"); + + return first != std::string::npos && sv.substr(first, 8) == "#include"; +} + +std::string parse_include(const std::string& line) { + auto pos = line.find("#include"); + auto start = line.find_first_of("<\"", pos); + auto end = line.find_first_of(">\"", start + 1); + + if (start == std::string::npos || end == std::string::npos) { + Logger::error("Invalid include: {}", line); + return {}; + } + return line.substr(start + 1, end - start - 1); +} + +void load_shader(std::string& source, const fs::path& file, + std::unordered_set& included) { + if (!fs::is_regular_file(file)) { + Logger::error("File {} don't Exist!", file.string()); + return; + } + auto canon = fs::canonical(file); + if (!included.insert(canon).second) { + return; + } + std::ifstream in(file); + if (!in.is_open()) { + Logger::error("Can't open {}", file.string()); + return; + } + std::string line; + while (std::getline(in, line)) { + if (is_include(line)) { + + auto include_file = file.parent_path() / parse_include(line); + source += "// begin include "; + source += include_file.string(); + source += "\n"; + load_shader(source, include_file, included); + source += "// end include "; + source += include_file.string(); + source += "\n"; + } else { + source.append(line + "\n"); + } + } +} + +} // namespace + namespace Tools { GLuint create_shader_program(const std::string& v_shader_path, @@ -102,19 +161,9 @@ bool check_opengl_error() { std::string read_shader_source(const std::string& file_path) { std::string content; - std::ifstream file_stream(file_path, std::ios::in); - - if (!file_stream.is_open()) { - Logger::error("{} not exist", file_path); - } - - std::string line = ""; - while (!file_stream.eof()) { - - getline(file_stream, line); - content.append(line + "\n"); - } - file_stream.close(); + fs::path path(file_path); + std::unordered_set included; + load_shader(content, path, included); return content; }