When I started teaching undergraduate C programming during my master’s program, I did a lot of thinking about how I felt when I was a student sitting in these same classes just a few years before. And that time was characterised for me, as I’m sure it is for many students, by an overarching sense that this wasn’t “real” computer programming. All input and output in the course was performed through the terminal, but half of us had never even seen the terminal used before, and we certainly weren’t regularly running programs from one. In consumer software, the GUI reigns supreme. Is it any wonder I felt like the computer programming I was learning was somehow at odds with my experience as a user of software?
Of course, this line of thinking betrays some naivety in my younger self, but the problem was a valid one: when your audience is accustomed to interacting with a computer graphically, how do you make them feel empowered by what they’ve learned using purely text-based I/O? With this objective in mind, I wanted to produce a demonstration for the class that looked flashy and impressive, but required extensive computation to get there. This way, I would hopefully be able to convince a flock of disinterested undergraduates that they were most of the way toward being able to produce the sort of computer program they most strongly relate to.
I was lucky in one respect, since the course in question, being geared toward programming for engineers, featured a significant unit on numerical methods. All these students had just learned how to write numerical ODE solvers, which lie at the core of a wealth of physical simulations. Are physical sims computationally intensive? Check. Do they produce flashy and impressive results? You betcha. Is it within the capabilities of these students to write one? Well, they’ll be able to understand the code if it’s given to them, at any rate.
Aforementioned flashy and impressive results of physical simulations
I figured that a cloth simulation struck the perfect balance between complexity and spectacle. It’s effectively a solved problem at this point, with some implementations producing impressively realistic results (see below). So while it mightn’t have been the most revolutionary project, I knew that the problem was well-documented with plenty of supporting material, which was beneficial for a class demonstration. There are models of varying complexity, and the simpler ones are easy to follow without seeming trivial.
The model selected treats the cloth as a set of point masses connected by springs. The good thing here was that it could be explained in terms of processes that required only a high school level of physics knowledge, and it was possible, without changing the underlying model, to add additional dynamics that improve accuracy if so desired.
All cloth in this surreal video is computer-generated
So at its core, the cloth is effectively a grid of particles, with each particle connected to its 8 immediate neighbours by springs like so:
How do you obtain the dynamics of a model like this? If we have the position of each particle at a given instant in time, we can assume that the position a very short time later will be roughly this position plus the instantaneous velocity times that very short period of time. Congratulations, you’ve just understood how an ODE solver works. But to follow this method, we need to obtain an estimate of the velocity of each particle by summing the forces acting on them. We divide by mass, and presto, there’s an acceleration we can use to obtain an estimate of the velocity. How good is Newton’s Second Law?
The forces we’d consider (at a minimum) to be acting on each particle are a weight force, and the 8 contributions from the 8 springs connected to it.
If we wanted to model wind or collisions or whatever, we could add that as well. But essentially, the evolution of the system involves computing, for each time instant, the net force acting on each vertex; from this determining the acceleration vector; and from that finding the velocity and position vectors.
The weight force is easy, that’s just a constant -9.8_m_ in the z direction.
The springs are a little trickier. The force on a damped spring is resistant to both the amount it is currently stretched by, x, and its current instantaneous velocity, v. The formula is therefore:
F = -kx-cv
where k and c are constants.
Visualisation of the forces acting on a damped spring
There’s some trickiness here because the velocity in this case is the relative velocity between the two neighbouring particles. In any case, do that 8 times, once for each immediate neighbour, and sum the results to get the net force on the particle.
Armed with these formulae and this model, I was able to put together a decent cloth simulation. In practise, I used a slightly more complex ODE solver called a Runge-Kutta solver, which made the simulation more robust, and less prone to instability. Given that this is the solver the students are taught about, using it was a great learning opportunity.
For output, I just printed the resulting data to the terminal, one line to a time instant. Remember that the point of this program is to emphasise the importance of the computation itself, and I think it does a good job of that. A lot of effort goes into producing the numbers that are produced as output, both computational resources and mental effort in designing the program.
But of course, if we can produce pretty pictures from this, we ought to. So, by writing some supplementary scripts, I took the output of the solver and rendered a series of frames using pbrt, which I stitched into a video.
Fantastic stuff. And here’s the thing, there really wasn’t much post-processing necessary to get that result. I want to be able to convince any student starting their computer science journey that something like this is within their grasp. The renderer isn’t the important part of producing that video, our program is, because without it, there’s nothing to render.
By the way, this simulation is far from perfect: there are a number of avenues to explore here to make our simulation more robust or accurate or versatile. We could check for self-intersections of the cloth, we can add additional springs to our model to prevent sharp edges forming at vertices, we could model collisions with solid objects, or add external forces such as wind. The code’s all public on Github; feel free to clone it and make some improvements.
So how did this go down? Well, I showed it to students, and a lot were duly impressed, which is of course flattering and encouraging, but it’s not something I’m all that interested in. Because the real metric for success is whether or not they believed it was within their abilities to do the same, and I hope they did.
When you learn to program for the first time, you get this feeling that all your projects are just tiny parts of ‘real’ programs; or toy examples that don’t mean anything. So I think it’s increasingly important to keep students feeling like what they’re being taught is actually relevant in some way. By giving them examples of how their code might fit into some bigger picture, we empower them not just to continue studies in the field, but to start playing around with programming and perhaps end up making something incredible.