diff --git a/projects/particle_simulation/CMakeLists.txt b/projects/particle_simulation/CMakeLists.txt
index 2e62c66e72f4eea9434acf4b1c4f26f739b5d989..35af9b32870ccafce13397c75c503197eb453c36 100644
--- a/projects/particle_simulation/CMakeLists.txt
+++ b/projects/particle_simulation/CMakeLists.txt
@@ -24,7 +24,7 @@ if(MSVC)
 endif()
 
 # including headers of dependencies and the VkCV framework
-target_include_directories(particle_simulation SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include})
+target_include_directories(particle_simulation SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include})
 
 # linking with libraries from all dependencies and the VkCV framework
-target_link_libraries(particle_simulation vkcv vkcv_testing vkcv_camera)
+target_link_libraries(particle_simulation vkcv vkcv_testing vkcv_camera vkcv_shader_compiler)
diff --git a/projects/particle_simulation/shaders/tonemapping.comp b/projects/particle_simulation/shaders/tonemapping.comp
new file mode 100644
index 0000000000000000000000000000000000000000..4ba7f2c661a0549e9852e30b9140811852ddbdbd
--- /dev/null
+++ b/projects/particle_simulation/shaders/tonemapping.comp
@@ -0,0 +1,19 @@
+#version 440
+
+layout(set=0, binding=0, rgba16f)   uniform image2D inImage;
+layout(set=0, binding=1, rgba8)     uniform image2D outImage;
+
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+void main(){
+
+    if(any(greaterThanEqual(gl_GlobalInvocationID.xy, imageSize(inImage)))){
+        return;
+    }
+    ivec2 uv            = ivec2(gl_GlobalInvocationID.xy);
+    vec3 linearColor    = imageLoad(inImage, uv).rgb;
+    vec3 tonemapped     = linearColor / (linearColor + 1); // reinhard tonemapping
+    vec3 gammaCorrected = pow(tonemapped, vec3(1.f / 2.2f));
+    imageStore(outImage, uv, vec4(gammaCorrected, 0.f));
+}
\ No newline at end of file
diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp
index b2eb5bc59581795502c0b7df0ed63eca57df01d6..73e112da16f1767f9ca0d9222b3f7f36049e4eb1 100644
--- a/projects/particle_simulation/src/main.cpp
+++ b/projects/particle_simulation/src/main.cpp
@@ -7,6 +7,7 @@
 #include <random>
 #include <glm/gtc/matrix_access.hpp>
 #include <time.h>
+#include <vkcv/shader/GLSLCompiler.hpp>
 
 int main(int argc, const char **argv) {
     const char *applicationName = "Particlesystem";
@@ -36,12 +37,12 @@ int main(int argc, const char **argv) {
     uint16_t indices[3] = {0, 1, 2};
     particleIndexBuffer.fill(&indices[0], sizeof(indices));
 
-
+    vk::Format colorFormat = vk::Format::eR16G16B16A16Sfloat;
     // an example attachment for passes that output to the window
     const vkcv::AttachmentDescription present_color_attachment(
             vkcv::AttachmentOperation::STORE,
             vkcv::AttachmentOperation::CLEAR,
-            core.getSwapchain().getFormat());
+            colorFormat);
 
 
     vkcv::PassConfig particlePassDefinition({present_color_attachment});
@@ -206,6 +207,19 @@ int main(int argc, const char **argv) {
     cameraManager.getCamera(camIndex1).setPosition(glm::vec3(0.0f, 0.0f, -2.0f));
     cameraManager.getCamera(camIndex1).setCenter(glm::vec3(0.0f, 0.0f, 0.0f));
 
+    vkcv::Image colorBuffer = core.createImage(colorFormat, windowWidth, windowHeight, 1, false, true, true);
+
+    vkcv::ShaderProgram tonemappingShader;
+    vkcv::shader::GLSLCompiler compiler;
+    compiler.compile(vkcv::ShaderStage::COMPUTE, "shaders/tonemapping.comp", [&](vkcv::ShaderStage shaderStage, const std::filesystem::path& path) {
+        tonemappingShader.addShader(shaderStage, path);
+    });
+
+    vkcv::DescriptorSetHandle tonemappingDescriptor = core.createDescriptorSet(tonemappingShader.getReflectedDescriptors()[0]);
+    vkcv::PipelineHandle tonemappingPipe = core.createComputePipeline(
+        tonemappingShader, 
+        { core.getDescriptorSet(tonemappingDescriptor).layout });
+
     std::uniform_real_distribution<float> rdm = std::uniform_real_distribution<float>(0.95f, 1.05f);
     std::default_random_engine rdmEngine;
     while (window.isWindowOpen()) {
@@ -252,7 +266,30 @@ int main(int argc, const char **argv) {
                 particlePipeline,
                 pushConstantDataDraw,
                 {drawcalls},
-                {swapchainInput});
+                { colorBuffer.getHandle() });
+
+        core.prepareImageForStorage(cmdStream, colorBuffer.getHandle());
+        core.prepareImageForStorage(cmdStream, swapchainInput);
+
+        vkcv::DescriptorWrites tonemappingDescriptorWrites;
+        tonemappingDescriptorWrites.storageImageWrites = {
+            vkcv::StorageImageDescriptorWrite(0, colorBuffer.getHandle()),
+            vkcv::StorageImageDescriptorWrite(1, swapchainInput)
+        };
+        core.writeDescriptorSet(tonemappingDescriptor, tonemappingDescriptorWrites);
+
+        uint32_t tonemappingDispatchCount[3];
+        tonemappingDispatchCount[0] = std::ceil(windowWidth / 8.f);
+        tonemappingDispatchCount[1] = std::ceil(windowHeight / 8.f);
+        tonemappingDispatchCount[2] = 1;
+
+        core.recordComputeDispatchToCmdStream(
+            cmdStream, 
+            tonemappingPipe, 
+            tonemappingDispatchCount, 
+            {vkcv::DescriptorSetUsage(0, core.getDescriptorSet(tonemappingDescriptor).vulkanHandle) },
+            vkcv::PushConstantData(nullptr, 0));
+
         core.prepareSwapchainImageForPresent(cmdStream);
         core.submitCommandStream(cmdStream);
         core.endFrame();