hachem.wtf
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2025-08-22 04:48:42 +0200
committerhachem <im@hachem.wtf>2025-08-22 04:48:42 +0200
commit77717ae7c4f7c8f180e5c5e24cf1098c02f3dbf4 (patch)
tree61ef3218a5e1f46e13b10cea3141f2eeee81bd7c
parent2dd07499241638e66ee0df97cba91219f5599151 (diff)
feat: add bloom and blur
-rw-r--r--assets/shaders/blur.glsl60
-rw-r--r--assets/shaders/geodesic.glsl20
-rw-r--r--src/engine/engine.cpp19
-rw-r--r--src/engine/engine.h12
-rw-r--r--src/states/simulation_state.cpp16
5 files changed, 120 insertions, 7 deletions
diff --git a/assets/shaders/blur.glsl b/assets/shaders/blur.glsl
new file mode 100644
index 0000000..984f0ba
--- /dev/null
+++ b/assets/shaders/blur.glsl
@@ -0,0 +1,60 @@
+#type vertex
+
+#version 330 core
+
+layout (location = 0) in vec2 a_Pos;
+layout (location = 1) in vec2 a_TexCoord;
+
+out vec2 v_TexCoord;
+
+void main()
+{
+ gl_Position = vec4(a_Pos, 0.0, 1.0);
+ v_TexCoord = a_TexCoord;
+}
+
+#type fragment
+
+#version 330 core
+
+in vec2 v_TexCoord;
+out vec4 o_FragColor;
+
+uniform sampler2D u_ScreenTexture;
+uniform vec2 u_Resolution;
+uniform float u_BlurStrength;
+uniform float u_GlowIntensity;
+
+void main()
+{
+ vec2 texelSize = 1.0 / u_Resolution;
+ vec4 centerColor = texture(u_ScreenTexture, v_TexCoord);
+
+ float brightness = (centerColor.r + centerColor.g + centerColor.b) / 3.0;
+ float glowMask = smoothstep(0.05, 0.3, brightness);
+
+ vec4 blurredColor = vec4(0.0);
+ float totalWeight = 0.0;
+
+ for (int x = -8; x <= 8; x++)
+ {
+ for (int y = -8; y <= 8; y++)
+ {
+ vec2 offset = vec2(x, y) * texelSize * u_BlurStrength;
+ vec4 sampleColor = texture(u_ScreenTexture, v_TexCoord + offset);
+
+ float weight = exp(-(x*x + y*y) / (2.0 * 8.0 * 8.0));
+ blurredColor += sampleColor * weight;
+ totalWeight += weight;
+ }
+ }
+
+ blurredColor /= totalWeight;
+
+ vec3 emissionColor = vec3(1.0, 0.8, 0.6);
+ vec3 glowColor = emissionColor * glowMask * u_GlowIntensity * 2.0;
+ vec3 auraColor = blurredColor.rgb * glowMask * u_GlowIntensity * 0.8;
+ vec3 finalColor = centerColor.rgb + glowColor + auraColor;
+
+ o_FragColor = vec4(finalColor, centerColor.a);
+}
diff --git a/assets/shaders/geodesic.glsl b/assets/shaders/geodesic.glsl
index eba7213..70e41ef 100644
--- a/assets/shaders/geodesic.glsl
+++ b/assets/shaders/geodesic.glsl
@@ -323,7 +323,10 @@ vec4 SampleDiskColor(vec3 pos)
float brightness_medium = fbm(rotated_brightness_pos * 5.0, 2);
float brightness_small = fbm(rotated_brightness_pos * 7.0, 2);
float brightness_noise = (brightness_large * 0.6 + brightness_medium * 0.3 + brightness_small * 0.1);
- float brightness = 1.0 + density * 1.0 + brightness_noise * 0.4;
+
+ float baseBrightness = 1.0 + density * 1.5;
+ float glowBrightness = brightness_noise * 0.8;
+ float brightness = baseBrightness + glowBrightness;
return vec4(baseColor * brightness, density);
}
@@ -413,14 +416,21 @@ void main()
vec3 diskColor = diskSample.rgb;
float stepLength = currentStepSize * 1e-8;
- float absorption = density * stepLength * 1.2;
- float scattering = density * stepLength * 0.8;
+
+ float absorption = density * stepLength * 0.8;
+ float scattering = density * stepLength * 1.5;
float extinction = absorption + scattering;
float stepTransmittance = exp(-extinction);
- vec3 emission = diskColor * density * stepLength * 2.5 * sqrt(disk_density);
- accumulatedColor.rgb += emission * transmittance;
+ vec3 emission = diskColor * density * stepLength * 4.0 * sqrt(disk_density);
+
+ vec3 glowColor = mix(diskColor, vec3(1.0, 0.8, 0.6), 0.3);
+ float glowIntensity = density * stepLength * 2.0;
+ vec3 atmosphericGlow = glowColor * glowIntensity * 0.8;
+
+ vec3 totalEmission = emission + atmosphericGlow;
+ accumulatedColor.rgb += totalEmission * transmittance;
transmittance *= stepTransmittance;
diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp
index 435b3e0..9a88e9e 100644
--- a/src/engine/engine.cpp
+++ b/src/engine/engine.cpp
@@ -34,6 +34,7 @@ namespace Donut
m_shader_program = Ref<Shader>(Shader::create("assets/shaders/compute_texture_quad.glsl"));
m_compute_program = create_compute_program("assets/shaders/geodesic.glsl");
+ m_blur_shader = Ref<Shader>(Shader::create("assets/shaders/blur.glsl"));
m_camera_ubo = UniformBuffer::create(128, 1);
m_disk_ubo = UniformBuffer::create(sizeof(float) * 5, 2);
@@ -96,6 +97,24 @@ namespace Donut
RenderCommand::enable_depth_test();
}
+ void Engine::draw_blur_pass()
+ {
+ RenderCommand::set_viewport(0, 0, m_width, m_height);
+
+ m_blur_shader->bind();
+ m_quad_vao->bind();
+
+ m_texture->bind(0);
+ m_blur_shader->set_int("u_ScreenTexture", 0);
+ m_blur_shader->set_float2("u_Resolution", glm::vec2(m_width, m_height));
+ m_blur_shader->set_float("u_BlurStrength", m_blur_strength);
+ m_blur_shader->set_float("u_GlowIntensity", m_glow_intensity);
+
+ RenderCommand::disable_depth_test();
+ RenderCommand::draw_arrays(6);
+ RenderCommand::enable_depth_test();
+ }
+
void Engine::dispatch_compute(const Camera& cam)
{
int cw = get_compute_width();
diff --git a/src/engine/engine.h b/src/engine/engine.h
index 524f1a7..95cd1f0 100644
--- a/src/engine/engine.h
+++ b/src/engine/engine.h
@@ -66,6 +66,7 @@ namespace Donut
~Engine() = default;
void draw_full_screen_quad();
+ void draw_blur_pass();
void dispatch_compute(const Camera& cam);
void upload_camera_ubo(const Camera& cam);
void upload_objects_ubo(const std::vector<ObjectData>& objs);
@@ -109,6 +110,12 @@ namespace Donut
float get_rotation_speed() const { return m_rotation_speed; }
void set_rotation_speed(float speed) { m_rotation_speed = speed; }
+ float get_blur_strength() const { return m_blur_strength; }
+ void set_blur_strength(float strength) { m_blur_strength = strength; }
+
+ float get_glow_intensity() const { return m_glow_intensity; }
+ void set_glow_intensity(float intensity) { m_glow_intensity = intensity; }
+
void load_objects_from_scene(const std::vector<Donut::Object>& objects);
void export_high_res_frame(const std::string& filename, int width = 4096, int height = 3072);
void print_object_info() const;
@@ -120,6 +127,7 @@ namespace Donut
Ref<Texture2D> m_texture;
Ref<Shader> m_shader_program;
Ref<Shader> m_compute_program;
+ Ref<Shader> m_blur_shader;
Ref<UniformBuffer> m_camera_ubo;
Ref<UniformBuffer> m_disk_ubo;
Ref<UniformBuffer> m_objects_ubo;
@@ -145,7 +153,9 @@ namespace Donut
float m_early_exit_distance = 5e11f;
float m_disk_thickness = 0.1;
- float m_disk_density = 1.2f;
+ float m_disk_density = 0.1f;
float m_rotation_speed = 1.0f;
+ float m_blur_strength = 2.0f;
+ float m_glow_intensity = 0.1f;
};
};
diff --git a/src/states/simulation_state.cpp b/src/states/simulation_state.cpp
index 5c75569..6d7ae47 100644
--- a/src/states/simulation_state.cpp
+++ b/src/states/simulation_state.cpp
@@ -60,7 +60,7 @@ namespace Donut
RenderCommand::set_viewport(0, 0, static_cast<uint32_t>(engine.get_width()), static_cast<uint32_t>(engine.get_height()));
engine.dispatch_compute(engine.get_camera());
- engine.draw_full_screen_quad();
+ engine.draw_blur_pass();
}
void SimulationState::on_event(Event& event)
@@ -244,6 +244,20 @@ namespace Donut
}
ImGui::TextDisabled("Rotation speed multiplier (0 = no rotation)");
+ float blur_strength = engine.get_blur_strength();
+ if (ImGui::SliderFloat("Blur Strength", &blur_strength, 0.5f, 5.0f, "%.2f"))
+ {
+ engine.set_blur_strength(blur_strength);
+ }
+ ImGui::TextDisabled("Blur radius for glow effect");
+
+ float glow_intensity = engine.get_glow_intensity();
+ if (ImGui::SliderFloat("Glow Intensity", &glow_intensity, 0.1f, 3.0f, "%.2f"))
+ {
+ engine.set_glow_intensity(glow_intensity);
+ }
+ ImGui::TextDisabled("Intensity of the glow effect");
+
ImGui::Spacing();
ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Camera");