Hair simulation with OpenGL
While revisiting some projects I developed in college, I found one I'm really proud of for simulating hair movement using OpenGL. I did it during my computer graphics course in 2016. OpenGL is a popular cross-platform rendering library you can actually use with different programming languages. At that time, I was really diving into the C++ ecosystem so that's the reason it's written in C++. I'm not really going to explain implementation details although I've uploaded it in this GitHub repository, but I'll try to explain the big picture.
The idea here is to have a vector field to simulate gravitational force and another power source to disturb it. This other power source can be thought as a fan which is actually what's going to blow the hair. By the way, simulating hair and its response to the forces applied to it are perhaps the most challenging parts of this project. So first, let's get to how we simulate hair using Bézier curves.
Bézier curve
A Bézier curve is used for representing smooth lines which are obtained from a set of control points. The control points are crucial because the resulting line will be obtained by interpolating them. If a Bézier curve only has two control points, the result will be a straight line. So it gets interesting when it has three control points or more. This is perfect for what we intend and this is how a hair is represented here.
Given a set of control points, one can think of iterating over the distance between the starting and ending points by mapping it to a interval between 0 and 1. By doing this, we can start from point 0 and calculate the next points according to current iteration of the interval by interpolating all control points. The following equation is used to calculate the x coordinate of the resulting curve at iteration t. This calculation needs to be done for each coordinate that applies (e.g. x, y, and z).
If I could say something about the intuition behind this equation, is the following: notice that the points closer to the current iteration are the ones contributing the most for the result (e.g. iterations close to 0 will take into account the first control points similar happens to iterations close to 0.5 and 1). The following illustrates how a Bézier curve with three control points is obtained.
In this project, we used ten points for each hair. One can choose to use more or less than ten but it turned out to be a good number along with some other parameters used.
Next, we're going to overview each implementation model and how they relate.
Vector field model
Although it impacts the whole simulation, this is actually one of the simplest models. A vector field has a property called force which represents how hard it'll impact the objects. You can see it as the gravity force. The vector field model provides methods for calculating the resulting coordinates of a given point in the space. So given a point (u, v, w) in the third dimension, the vector field will return a new point obtained from applying its force in a certain direction defined as another property in the vector field model.
Power source model
This model is responsible for disturbing the vector field. In fact, it acts as a special vector field which is limited to an area around it whose radius depends on the distance to its center. The restricted area it affects is intended to simulate drag (air resistance). The fan here is represented by this light yellow square in the center of the next picture. Notice the points close to it are more affected than points farther from its center.
Hair model
Alright, here's the fun part. So in order to simulate the hair being blown by the fan and it returning back to its initial state, we of course need to store its initial position. We also have to store a delay value which represents the speed the hair will return to its initial state after it's been translated by power source. The lower the delay, the faster it'll return to its initial state. Another parameter to take into account is a ratio value between 0 and 1 which is going to tell how much it'll update at each instant of time(defined by the delay value). So that explains how we're returning the hair to its initial position after some disturbance. Now let's see how it can be disturbed and how it returns back to its initial position by dragging it manually.
After abstracting how the resulting line is drawn, we can focus on shifting the points representing it so we can replicate the blowing action. In order to do that, each hair object stores a reference to the vector field in the simulation and another one to the power source. With that, we can calculate the resultant force and direction from the combination of the vector field and power source for each hair object . The resultant force will be obtained from the sum of the vector field and the power source for each coordinate.
Here are some clips of the final result with different vector fields. Of course it isn't perfect but it's somewhat impressive we can achieve this from square one. There are a couple of stuff that could still be done. I believe some different parameters might improve the result. Besides that, some other behaviors could be added and tested. I remember the last thing I was trying to improve was making calculations run in parallel.
Another clear application of this model would be observing how objects would behave in space. This could be achieved by making the power source dragging objects to its center instead of blowing them away. Hit me up if you can think of any other improvements or if you want to know more about this project and contribute to it. Again, the source code is available in this GitHub repository. Feel free to test it or just play around with it.