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
This commit is contained in:
zhenyan121
2026-06-23 10:27:17 +08:00
committed by GitHub
parent 97993b72fe
commit d5a12869e6
11 changed files with 142 additions and 198 deletions

View File

@@ -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;
}

25
assets/shaders/noise.glsl Normal file
View File

@@ -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;
}

View File

@@ -19,84 +19,12 @@ uniform float cloudThresholdHigh;
uniform float time; uniform float time;
#include "compute_sky_color.glsl"
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;
}
void main(void) { void main(void) {
vec3 sky = computeSkyColor(dir); vec3 sky = computeSkyColor(dir);
frag_color = vec4(sky, 1.0); frag_color = vec4(sky, 1.0);
//frag_color = vec4(vec3(sunAmount), 1.0);
//frag_color = vec4(t,0,0,1);
} }

View File

@@ -19,33 +19,7 @@ uniform vec3 sunDir;
uniform vec3 sunColor; uniform vec3 sunColor;
uniform float waterDensity; uniform float waterDensity;
float hash(vec2 p) { #include "noise.glsl"
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;
}
float getCausticValue(float x, float y, float z) { float getCausticValue(float x, float y, float z) {
float w = 8.0; float w = 8.0;

View File

@@ -42,82 +42,15 @@ uniform float refractStrength;
uniform bool enablePerturb; uniform bool enablePerturb;
uniform bool enableDepthFade; uniform bool enableDepthFade;
#include "compute_sky_color.glsl"
float weight(float z, float a) { float weight(float z, float a) {
float intermediate = 0.03 / (1e-5 + pow(z / 200.0, 4.0)); float intermediate = 0.03 / (1e-5 + pow(z / 200.0, 4.0));
return a * clamp(intermediate, 1e-2, 3e2); 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 // Reconstruct eye-space coordinates from screen UV and depth buffer value
vec3 reconstructViewPos(vec2 uv, float depth) { vec3 reconstructViewPos(vec2 uv, float depth) {

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include "Cubed/gameplay/chunk_pos.hpp"
#include "Cubed/gameplay/path_point.hpp" #include "Cubed/gameplay/path_point.hpp"
#include "Cubed/tools/cubed_random.hpp" #include "Cubed/tools/cubed_random.hpp"
@@ -9,8 +8,6 @@
namespace Cubed { namespace Cubed {
class CavePath { class CavePath {
using ChunkPosSet =
tbb::concurrent_hash_map<ChunkPos, bool, ChunkPos::TBBHash>;
public: public:
CavePath(unsigned int chunk_seed, unsigned world_seed, CavePath(unsigned int chunk_seed, unsigned world_seed,

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include "Cubed/gameplay/chunk_pos.hpp"
#include "Cubed/gameplay/path_point.hpp" #include "Cubed/gameplay/path_point.hpp"
#include "Cubed/tools/cubed_random.hpp" #include "Cubed/tools/cubed_random.hpp"
@@ -9,8 +8,6 @@
namespace Cubed { namespace Cubed {
class RiverPath { class RiverPath {
using ChunkPosSet =
tbb::concurrent_hash_map<ChunkPos, bool, ChunkPos::TBBHash>;
public: public:
RiverPath(unsigned int chunk_seed, unsigned world_seed, RiverPath(unsigned int chunk_seed, unsigned world_seed,
@@ -46,8 +43,6 @@ private:
Random m_random; Random m_random;
std::vector<PathPoint> m_points; std::vector<PathPoint> m_points;
ChunkPosSet m_pending_chunks;
void collect_path_points(); void collect_path_points();
void precompute_chunk_coverage();
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "Cubed/gameplay/chunk_pos.hpp" #include "Cubed/gameplay/chunk_pos.hpp"
#include "Cubed/gameplay/path.hpp" #include "Cubed/gameplay/path.hpp"
#include "Cubed/tools/cubed_random.hpp"
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <tbb/concurrent_hash_map.h> #include <tbb/concurrent_hash_map.h>
@@ -25,7 +24,6 @@ public:
private: private:
std::atomic<unsigned> m_world_seed{0}; std::atomic<unsigned> m_world_seed{0};
Random m_random;
std::atomic<float> m_probability{0.01f}; std::atomic<float> m_probability{0.01f};
}; };

View File

@@ -7,11 +7,7 @@ namespace Cubed {
RiverWorm::RiverWorm() {} RiverWorm::RiverWorm() {}
RiverWorm::~RiverWorm() {} RiverWorm::~RiverWorm() {}
void RiverWorm::init(unsigned world_seed) { void RiverWorm::init(unsigned world_seed) { m_world_seed = world_seed; }
m_world_seed = world_seed;
m_random.init(m_world_seed);
}
void RiverWorm::reload(unsigned world_seed) { void RiverWorm::reload(unsigned world_seed) {

View File

@@ -63,6 +63,9 @@ void VertexData::upload() {
glEnableVertexAttribArray(5); glEnableVertexAttribArray(5);
glBindVertexArray(0); glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
// Release memory
m_vertices.clear();
} }
void VertexData::update_sum() { m_sum = m_vertices.size(); } void VertexData::update_sum() { m_sum = m_vertices.size(); }
} // namespace Cubed } // namespace Cubed

View File

@@ -5,11 +5,70 @@
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <unordered_set>
namespace Cubed { namespace Cubed {
namespace fs = std::filesystem; 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<fs::path>& 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 { namespace Tools {
GLuint create_shader_program(const std::string& v_shader_path, 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 read_shader_source(const std::string& file_path) {
std::string content; std::string content;
std::ifstream file_stream(file_path, std::ios::in); fs::path path(file_path);
std::unordered_set<fs::path> included;
if (!file_stream.is_open()) { load_shader(content, path, included);
Logger::error("{} not exist", file_path);
}
std::string line = "";
while (!file_stream.eof()) {
getline(file_stream, line);
content.append(line + "\n");
}
file_stream.close();
return content; return content;
} }