Jackson Kruger
The source code for these simulations can be found on Github. The code for the cloth simulation can be found here and the code for the fluid simulation can be found here. A zip of the compiled executables and supporting files for the two simulations can be downloaded here. I wrote my cloth simulation with C++ OpenGL (with a compute shader), while I wrote my eulerian fluid in Processing.
I implemented my cloth simulation in C++ OpenGL, performing all physics computation inside a GLSL compute shader. After initializing the necessary buffer objects for
the compute shader, all the CPU does is receive user input, call the compute shader, and render the scene. The mesh for the cloth updates purely through the beauty of
OpenGL VAOs, only needing an additional index buffer object to specify how to turn the positions and normals arrays on the compute shader into a mesh. After setup, the
cloth's mesh updates purely on the GPU, without meaningful CPU interference.
In the compiled demo, and the following video, the cloth consists of 128x180 masses connected vertically and horizontally by springs. The cloth updates with a dt value of 0.00002,
requiring about 833 physics updates per frame. For each of these iterations, the compute shader runs once per each of the 23,040 masses and computes accelerations. After a memory
barrier to sync the parallel executions, another compute is performed per mass to apply accelerations to positions and calculate new normals.
Note in this video the scale of the cloth compared to the 'scale person' shown behind it. This cloth is probably something like 30 meters tall.
General Cloth Demo
Several integration methods were attempted for the cloth. The following video compares the Eulerian, Midpoint, and RK4 integration methods.
In the end, I used the Midpoint method as I could not notice a significant improvement going from Midpoint to RK4, while RK4 had a noticeable impact on framerate.
Note that the videos do in fact start at the same time. Watch the "Sim Running" text in the title bar to confirm this.
Integration Methods Comparison
The cloth does include a drag term, though it's not physically accurate. The drag term's code can be found on
this line of the code.
It opposes the velocity of the cloth in the direction of the normal, but does not scale with the area of the cloth. The following two videos compare the cloth falling with and without
this drag term. The drag term is also most of the reason the cloth in the general demo above eventually 'settles down'.
With Drag (left) / Without Drag (right) Comparison
The biggest challenge faced during implementation was relatively early on, when I had designed my compute shader to run once per spring, instead of once per mass (this seemed
cleaner to me, architecturally). This lead to race conditions, as I was storing velocities/accelerations per-mass, and multiple springs were attached to each mass.
The race condition manifested by the cloth gradually spinning out of control, as shown in the video below. The solution was to redesign the compute shader to run per-mass, removing altogether the
chance for race conditions. (for this video, the masses are the brown spheres, springs are not rendered)
Spinning Out of Control
This cloth simulation is based on OpenGL with a GLSL compute shader. I wrote it for Windows in Visual Studio. SDL is used to interface with Windows. The library SDL_Image is used to load .png textures. Glad is used as an interface to OpenGL. The texture for the cloth comes from the user "achaley" on DeviantArt.
I had originally hoped to write a nice 3D compute-shader based eulerian fluid simulation (with surface tracking and probably raymarching), but it turns out that's really, really hard.
So, I settled for writing a 2D Eulerian fluid simulation in Processing, based on Jos Stam's paper
"Real-Time Fluid Dynamics for Games" in Processing. I didn't get the chance to port this over to
the fast world of C++ OpenGL compute shaders, so performance in this demo is quite poor. Nonetheless, the following video demonstrates my 2D Eulerian fluid simulation. The red lines
I turn on at 0:18 point the direction of the fluid's velocity for each cell. Black is the least dense, followed by blue, then teal, then white. I adjust the thresholds between these
colors at 0:29 in the video to show contours in the increasingly dense fluid.
General Fluid Demo
I tried to add gravity to the simulation, and it somewhat worked, but wasn't quite right, because the edge between fluid and no fluid is not tracked.
'Water' with 'Gravity'
The simulation is written in Processing. My implementation was based heavily on Jos Stam's paper "Real-Time Fluid Dynamics for Games", and was also informed by this ProcessingJS implementation I found.
Cloth | |
---|---|
Key(s) | Effect |
Right click | Rotate Camera |
WASD, R/F | Move camera forward, left, back, right, up, and down |
Left click | Move sphere |
-/= | Change distance of sphere from camera |
Space | Play/pause simulation |
Fluid | |
---|---|
Key(s) | Effect |
Left click + drag | Add fluid/velocity |
Shift | Modifies left click to only apply velocity, not add fluid |
r | Reset simulation |
1/2 | Increase/decrease threshold for blue coloring |
3/4 | Increase/decrease threshold for green coloring |
5/6 | Increase/decrease threshold for red coloring |
This last video's bug still happens if either dimension of the cloth is exactly 64. I have no idea why.
All videos shown here (and more) can also be found on Google Drive.
Source code can be found on GitHub