diff --git a/projects/wobble_bobble/shaders/transform_particles_to_grid.comp b/projects/wobble_bobble/shaders/transform_particles_to_grid.comp
index defc9c3e246612bbd8138f8f7b25ff29002c416a..bfd902b52c038bff7f32dc2482a0ae9490561b20 100644
--- a/projects/wobble_bobble/shaders/transform_particles_to_grid.comp
+++ b/projects/wobble_bobble/shaders/transform_particles_to_grid.comp
@@ -29,6 +29,8 @@ void main()	{
         if (localOffset < particles.length()) {
             shared_particles[gl_LocalInvocationIndex] = particles[localOffset].minimal;
         } else {
+            shared_particles[gl_LocalInvocationIndex].position = vec3(0.0f);
+            shared_particles[gl_LocalInvocationIndex].size = 0.0f;
             shared_particles[gl_LocalInvocationIndex].velocity = vec3(0.0f);
             shared_particles[gl_LocalInvocationIndex].mass = 0.0f;
         }
diff --git a/projects/wobble_bobble/shaders/update_grid_forces.comp b/projects/wobble_bobble/shaders/update_grid_forces.comp
index cfb8e20100dca232534c338ab082fa9931ffe53e..4920e493fab3f26d40a59aa5cdb6fc41a6892917 100644
--- a/projects/wobble_bobble/shaders/update_grid_forces.comp
+++ b/projects/wobble_bobble/shaders/update_grid_forces.comp
@@ -1,18 +1,30 @@
 #version 450
 #extension GL_GOOGLE_include_directive : enable
 
+const float PI = 3.1415926535897932384626433832795;
+
 layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;
 
 #include "particle.inc"
 
 layout(set=0, binding=0, rgba32f) uniform image3D gridImage;
+layout(set=0, binding=1, std430) buffer particleBuffer {
+    Particle particles [];
+};
 
 layout( push_constant ) uniform constants {
     float t;
     float dt;
 };
 
+#define SHARED_PARTICLES_BATCH_SIZE 64
+
+shared Particle shared_particles [SHARED_PARTICLES_BATCH_SIZE];
+
 void main()	{
+    const vec3 position = (vec3(gl_GlobalInvocationID) + vec3(0.5f)) / imageSize(gridImage);
+    const float elasticity_module = 12.5f * 1000000.0f; // 10..15 = Wood
+
     memoryBarrierImage();
 
     vec4 gridSample = imageLoad(
@@ -23,7 +35,44 @@ void main()	{
     vec3 velocity = gridSample.xyz;
     float mass = gridSample.w;
 
-    velocity += vec3(0.0f, 0.0f, 0.0f) * dt;
+    vec3 force = vec3(0.0f);
+    uint offset = 0;
+
+    memoryBarrierBuffer();
+
+    for (offset = 0; offset < particles.length(); offset += SHARED_PARTICLES_BATCH_SIZE) {
+        uint localOffset = offset + gl_LocalInvocationIndex;
+
+        if (localOffset < particles.length()) {
+            shared_particles[gl_LocalInvocationIndex] = particles[localOffset];
+        } else {
+            shared_particles[gl_LocalInvocationIndex].minimal.position = vec3(0.0f);
+            shared_particles[gl_LocalInvocationIndex].minimal.size = 0.0f;
+            shared_particles[gl_LocalInvocationIndex].minimal.velocity = vec3(0.0f);
+            shared_particles[gl_LocalInvocationIndex].minimal.mass = 0.0f;
+            shared_particles[gl_LocalInvocationIndex].deformation = mat4(0.0f);
+        }
+
+        memoryBarrierShared();
+
+        for (uint i = 0; i < SHARED_PARTICLES_BATCH_SIZE; i++) {
+            float size = shared_particles[gl_LocalInvocationIndex].minimal.size;
+            float volume = 4.0f / 3.0f * PI * size * size * size;
+            mat3 deformation = mat3(shared_particles[gl_LocalInvocationIndex].deformation);
+
+            mat3 epsilon = deformation - mat3(1.0f);
+            mat3 delta = elasticity_module * epsilon;
+            mat3 delta_cauchy = determinant(deformation) * delta * inverse(transpose(deformation));
+
+            force -= (
+                volume *
+                delta_cauchy *
+                vec3(voxel_particle_weight(position, shared_particles[gl_LocalInvocationIndex].minimal))
+            );
+        }
+    }
+
+    velocity += force * dt / mass;
 
     bvec3 lowerID = lessThanEqual(gl_GlobalInvocationID, ivec3(0));
     bvec3 negativeVelocity = lessThan(velocity, vec3(0.0f));
diff --git a/projects/wobble_bobble/src/main.cpp b/projects/wobble_bobble/src/main.cpp
index 674af9b124c9fa2bd55047f47e1c3f3a33b3c995..f76a7d53d1f87f197db7ef31dd91be3e3e46a8a8 100644
--- a/projects/wobble_bobble/src/main.cpp
+++ b/projects/wobble_bobble/src/main.cpp
@@ -214,6 +214,7 @@ int main(int argc, const char **argv) {
 	{
 		vkcv::DescriptorWrites writes;
 		writes.storageImageWrites.push_back(vkcv::StorageImageDescriptorWrite(0, grid.getHandle()));
+		writes.storageBufferWrites.push_back(vkcv::BufferDescriptorWrite(1, particles.getHandle()));
 		core.writeDescriptorSet(updateGridForcesSets[0], writes);
 	}