feat(water): add noise-based caustics and configurable fog density

This commit is contained in:
2026-06-19 17:51:05 +08:00
parent 75cccf0c4c
commit e1eaf62f09
4 changed files with 52 additions and 5 deletions

View File

@@ -10,6 +10,45 @@ uniform bool u_underwater;
uniform vec3 u_waterColor;
uniform float u_fogDensity;
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;
}
float getCausticValue(float x, float y, float z) {
float w = 8.0;
float strength = 4.0;
vec2 coord = vec2(x, y) * w + z * 0.5;
float n = fbm(coord);
float caustic = pow(n, 3.0) * strength;
return caustic;
}
void main() {
vec4 original = texture(u_sceneTexture, TexCoord);
@@ -23,11 +62,12 @@ void main() {
distoredUV.x += sin(TexCoord.y * 15.0 + u_time * 5.0) * strength;
distoredUV.y += cos(TexCoord.x * 15.0 + u_time * 4.3) * strength;
distoredUV = clamp(distoredUV, 0.001, 0.999);
vec4 distorted = texture(u_sceneTexture, distoredUV);
vec4 distorted = texture(u_sceneTexture, distoredUV);
float rawCaustic = getCausticValue(TexCoord.x, TexCoord.y, u_time * 0.3);
float caustic = 0.5 + rawCaustic * 0.5;
vec3 causticLight = vec3(caustic * 0.9, caustic, caustic * 0.7);
float caustic = 0.9 + 0.1 * sin(TexCoord.x * 20.0 + u_time) * cos(TexCoord.y * 20.0 + u_time * 1.2);
vec3 causticLight = vec3(caustic, caustic * 0.95, caustic * 0.9);
//vec3 causticLight = vec3(1.0);
float fogFactor = clamp(1.0 - (TexCoord.y * u_fogDensity * 10.0), 0.0, 1.0);
vec3 mixed = mix(u_waterColor, distorted.rgb * causticLight, fogFactor);

View File

@@ -45,6 +45,7 @@ public:
float& cloud_threshold_low();
float& cloud_threshold_high();
float& refract_strength();
float& underwater_fog_density();
private:
struct ParallelLight {
@@ -152,6 +153,8 @@ private:
float m_refract_strength = 0.03f;
float m_underwater_fog_density = 0.08f;
ParallelLight m_parallel_light;
SkyUniform m_sky_uniform;
/*

View File

@@ -662,6 +662,9 @@ void DevPanel::show_shader_tab_item() {
ImGui::Checkbox("Water Perturb", &m_app.renderer().water_perturb());
ImGui::SameLine();
ImGui::Checkbox("WaterDepthFade", &m_app.renderer().water_depth_fade());
ImGui::SliderFloat("Underwater Fog Density",
&m_app.renderer().underwater_fog_density(), 0.0f,
1.0f);
ImGui::EndTabItem();
}
}

View File

@@ -443,7 +443,7 @@ void Renderer::render_underwater() {
shader.set_loc("u_time", static_cast<float>(glfwGetTime()));
shader.set_loc("u_underwater", m_camera.is_under_water());
shader.set_loc("u_waterColor", glm::vec3(0.1f, 0.25f, 0.35f));
shader.set_loc("u_fogDensity", 0.08f);
shader.set_loc("u_fogDensity", m_underwater_fog_density);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_screen_texture);
@@ -980,4 +980,5 @@ float& Renderer::cloud_speed() { return m_cloud_speed; }
float& Renderer::cloud_threshold_low() { return m_cloud_threshold_low; }
float& Renderer::cloud_threshold_high() { return m_cloud_threshold_high; }
float& Renderer::refract_strength() { return m_refract_strength; }
float& Renderer::underwater_fog_density() { return m_underwater_fog_density; }
} // namespace Cubed