If you're seeing this message, it means we're having trouble loading external resources on our website.

If you're behind a web filter, please make sure that the domains *.kastatic.org and *.kasandbox.org are unblocked.

# Air and fluid resistance

Diagram of fluid resistance around a plane
Friction also occurs when a body passes through a liquid or gas. This force has many different names, all really meaning the same thing: viscous force, drag force, fluid resistance. While the result is ultimately the same as our previous friction examples (the object slows down), the way in which we calculate a drag force will be slightly different. Let’s look at the formula:
F, start subscript, d, end subscript, equals, −, start fraction, 1, divided by, 2, end fraction, rho, v, squared, A, C, start subscript, d, end subscript, v, with, hat, on top
Now let’s break this down and see what we really need for an effective simulation in ProcessingJS, making ourselves a much simpler formula in the process.
• F, start subscript, d, end subscript refers to drag force, the vector we ultimately want to compute and pass into our applyForce() function.
• -1/2 is a constant: -0.5. This is fairly irrelevant in terms of our ProcessingJS world, as we will be making up values for other constants anyway. However, the fact that it is negative is important, as it tells us that the force is in the opposite direction of velocity (just as with friction).
• rho is the Greek letter rho, and refers to the density of the liquid, something we don’t need to worry about. We can simplify the problem and consider this to have a constant value of 1.
• v refers to the speed of the object moving. OK, we’ve got this one! The object’s speed is the magnitude of the velocity vector: velocity.mag(). And v, squared just means v squared or v, times, v.
• A refers to the frontal area of the object that is pushing through the liquid (or gas). An aerodynamic Lamborghini, for example, will experience less air resistance than a boxy Volvo. Nevertheless, for a basic simulation, we can consider our object to be spherical and ignore this element.
• C, start subscript, d, end subscript is the coefficient of drag, exactly the same as the coefficient of friction (μ). This is a constant we’ll determine based on whether we want the drag force to be strong or weak.
• v, with, hat, on top Look familiar? It should. This refers to the velocity unit vector, i.e. velocity.normalize(). Just like with friction, drag is a force that points in the opposite direction of velocity.
Now that we’ve analyzed each of these components and determined what we need for a simple simulation, we can reduce our formula to:
Simplified formula: F_drag = ||v^2|| * c_d * v - 1
or:
// Part 1 of our formula (magnitude): v^2 * Cd
var c = 0.1;
var speed = velocity.mag();
var dragMagnitude = c * speed * speed;

// Part 2 of our formula (direction): v unit vector * -1
var drag = velocity.get();
drag.normalize();
drag.mult(-1);

// Magnitude and direction together!
drag.mult(dragMagnitude);
Let’s implement this force in our Mover object type with one addition. When we wrote our friction example, the force of friction was always present. Whenever an object was moving, friction would slow it down. Here, let’s introduce an element to the environment—a “liquid” that the Mover objects pass through. The Liquid object will be a rectangle and will know about its location, width, height, and “coefficient of drag”—i.e., is it easy for objects to move through it (like air) or difficult (like molasses)? In addition, it should include a function to draw itself on the screen (and two more functions, which we’ll see in a moment).
var Liquid = function(x, y, w, h, c) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.c = c;
};

Liquid.prototype.display = function() {
noStroke();
fill(50);
rect(this.x, this.y, this.w, this.h);
};
The main program will now declare and initialize a new Liquid object instance. Note the coefficient is low (0.1), otherwise the object would come to a halt fairly quickly (which may someday be the effect you want).
var liquid = new Liquid(0, height/2, width, height/2, 0.1);
Now comes an interesting question: how do we get the Mover object to talk to the Liquid object? In other words, we want to execute the following:
When a mover passes through a liquid it experiences a drag force.
…or in object-oriented speak (assuming we are looping through an array of Mover objects with index i):
// Is the Mover in the liquid?
if (liquid.contains(movers[i])) {
// Calculate drag force
var dragForce = liquid.calculateDrag(movers[i]);
// Apply drag force to Mover
movers[i].applyForce(dragForce);
}
The above code tells us that we need to add two functions to the Liquid object type: (1) a function that determines if a Mover object is inside the Liquid object, and (2) a function that computes the drag force exerted on the Mover object.
The first is easy; we can simply use a conditional statement to determine if the location vector rests inside the rectangle defined by the liquid.
Liquid.prototype.contains = function(m) {
var p = m.position;
return p.x > this.x && p.x < this.x + this.w &&
p.y > this.y && p.y < this.y + this.h;
};
The drag() function is a bit more complicated; however, we’ve written the code for it already. This is simply an implementation of our formula. The drag force is equal to the coefficient of drag multiplied by the speed of the Mover squared in the opposite direction of velocity!
Liquid.prototype.calculateDrag = function(m) {
// Magnitude is coefficient * speed squared
var speed = m.velocity.mag();
var dragMagnitude = this.c * speed * speed;

// Direction is inverse of velocity
var dragForce = m.velocity.get();
dragForce.mult(-1);

// Scale according to magnitude
dragForce.normalize();
dragForce.mult(dragMagnitude);
return dragForce;
};
And with these two functions added to the Liquid object type, we’re ready to put it all together into one program:
Running the program, you should notice that we are simulating balls falling into water. The objects only slow down when crossing through the blue area at the bottom of the window (representing the liquid). You’ll also notice that the smaller objects slow down a great deal more than the larger objects. Remember Newton’s second law? A = F / M. Acceleration equals force divided by mass. A massive object will accelerate less. A smaller object will accelerate more. In this case, the acceleration we’re talking about is the “slowing down” due to drag. The smaller objects will slow down at a greater rate than the larger ones.

This "Natural Simulations" course is a derivative of "The Nature of Code" by Daniel Shiffman, used under a Creative Commons Attribution-NonCommercial 3.0 Unported License.

## Want to join the conversation?

• In the Sinking logs challenge how are you supposed to calculate the drag coefficient based on the log width if we haven't defined how long each log is?
• calculateDrag takes as its input 'm', which will ultimately be logs[i].
Use m.width to pull the width from logs[i] in the equation (which means ultimately you will be inserting logs[i].width).
• I noticed that objects bounce off the surface of the water when I play around with the coefficient of drag. Why is this happening and how can I fix it?
• Drag pushes back on forward movement. If you make the coefficient big enough (or the speed fast enough), the push-back overwhelms the forward movement. So how about
dragMagnitude = min(speed, dragMagnitude);
But, be aware in the real world something crashing into a viscous liquid at high speed may bounce off of it.
• I'm stuck on step 1. It keeps saying "You should always apply forces before the update method is called, so that the force has its effect first." Where did I go wrong? Here is my code.
var Liquid = function(x, y, w, h, c) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.c = c;
};

Liquid.prototype.contains = function(m) {
var l = m.position;
return l.x > this.x && l.x < this.x + this.w &&
l.y > this.y && l.y < this.y + this.h;
};

Liquid.prototype.calculateDrag = function(m) {
var speed = m.velocity.mag();
var dragMagnitude = this.c * speed * speed;

var dragForce = m.velocity.get();
dragForce.mult(-1);

dragForce.normalize();
dragForce.mult(dragMagnitude);
return dragForce;
};

Liquid.prototype.display = function() {
noStroke();
fill(126, 138, 242);
rect(this.x, this.y, this.w, this.h);
};

var Log = function(w, x, y) {
this.mass = 1;
this.position = new PVector(x, y);
this.velocity = new PVector(0, 0);
this.acceleration = new PVector(0, 0);
};

Log.prototype.applyForce = function(force) {
var f = PVector.div(force, this.mass);
};

Log.prototype.update = function(m) {
this.acceleration.mult(0);
};

Log.prototype.display = function() {
stroke(0, 0, 0);
strokeWeight(2);
fill(184, 150, 55);
rect(this.position.x, this.position.y, this.width, this.mass*16);
};

Log.prototype.checkEdges = function() {
if (this.position.y > height) {
this.velocity.y *= -1;
this.position.y = height;
}
};

var logs = [];
var liquid = new Liquid(0, height/2, width, height/2, 0.5);

for (var i = 0; i < 5; i++) {
logs[i] = new Log(20, 20+i*width/5, 0);
}

draw = function() {
background(235, 254, 255);
liquid.display();

for (var i = 0; i < logs.length; i++) {
var gravity = new PVector(0, 0.1*logs[i].mass);
logs[i].applyForce(gravity);
if (liquid.contains(logs[i])) {
var Arrastar = liquid.calcuateDrag(logs[i]);
logs[i].applyForce(Arrastar);
}
logs[i].update();
logs[i].display();
logs[i].checkEdges();
}
};
• if(liquid.contains(logs[i])) {      var c = liquid.calculateDrag(logs[i]);   logs[i].applyForce(c);}

I have no clue how these differ, but mine works.
• Will there ever be a course for object collisions and bouyancy?
• Oh! Hi didn't expect to see you here! :D

I know this comment is old. But this is what I used.
this.calcBuoyancy=function(m){        var weightOfDisplacedFluid = (this.y-m.position.y)*this.weight;//how deep * how heavy the liquid is        var apparentImmersedWeight = this.weight - weightOfDisplacedFluid;        var buoyancy = new PVector(0,-apparentImmersedWeight);        return buoyancy;};

It looks about right when use it in my simulator. You also have to set the Liquids weight. I keep it between
this.weight = 0.01; and this.weight = 0.05
It all depends on the properties of the liquid.
• Can someone please explain the code of the return statement of this function. it is about halfway through the page, and I have never seen one like this. Thank you!

Liquid.prototype.contains = function(m) {
var p = m.position;
return p.x > this.x && p.x < this.x + this.w &&
p.y > this.y && p.y < this.y + this.h;
};
• Can anyone help me with step two of sinking logs?
Here's my code so far:

for (var i = 0; i < 5; i++) {
logs[i] = new Log(logs[i].width, 20+i*width/5, 0);
}

I'm sure that this is right, but the grader won't accept it.
• It wants a random number. random(10,30)
• I am stuck on step one of the next challenge. I believe I have the right code, but there is still an orange prompt at the top that tells me to " apply forces before the update method is called, so that the force has its effect first." I tried moving the draw function before the update method, but that gave me an Oh Noes message. Any help would be greatly appreciated.
My code:
var Liquid = function(x, y, w, h, c) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.c = c;
};

Liquid.prototype.contains = function(m) {
var l = m.position;
return l.x > this.x && l.x < this.x + this.w &&
l.y > this.y && l.y < this.y + this.h;
};

Liquid.prototype.calculateDrag = function(m) {
var speed = m.velocity.mag();
var dragMagnitude = this.c * speed * speed;

var dragForce = m.velocity.get();
dragForce.mult(-1);

dragForce.normalize();
dragForce.mult(dragMagnitude);
return dragForce;
};

Liquid.prototype.display = function() {
noStroke();
fill(126, 138, 242);
rect(this.x, this.y, this.w, this.h);
};

var Log = function(w, x, y) {
this.mass = 1;
this.width = w;
this.position = new PVector(x, y);
this.velocity = new PVector(0, 0);
this.acceleration = new PVector(0, 0);
};

Log.prototype.applyForce = function(force) {
var f = PVector.div(force, this.mass);
};

Log.prototype.update = function() {
this.acceleration.mult(0);
};

Log.prototype.display = function() {
stroke(0, 0, 0);
strokeWeight(2);
fill(184, 150, 55);
rect(this.position.x, this.position.y, this.width, this.mass*16);
};

Log.prototype.checkEdges = function() {
if (this.position.y > height) {
this.velocity.y *= -1;
this.position.y = height;
}
};

var logs = [];
var liquid = new Liquid(0, height/2, width, height/2, 0.1);

for (var i = 0; i < 5; i++) {
logs[i] = new Log(20, 20+i*width/5, 0);

}
draw = function() {
background(235, 254, 255);
liquid.display();

for (var i = 0; i < logs.length; i++) {
var gravity = new PVector(0, 0.1*logs[i].mass);
logs[i].applyForce(gravity);
if (liquid.contains(logs[i])) {
var dragForce = logs.calculateForce(logs[i]);
logs[i].applyForce(dragForce);}
logs[i].update();
logs[i].display();
logs[i].checkEdges();
}
};
• Apologies for the untimely response. Your error was that you tried to execute the calculateForce() method on an array, logs where you should've invoked the calculateDrag() method on the liquid object. Cheers!
(1 vote)
• This is my code:

if(liquid.contains(logs[i])){
var dragForce = liquid.calculateDrag(logs[i]);
logs[i].applyForce(dragForce);
}

and Oh Noes keeps saying: "Cannot read property 'position' of undefined" I don't even have that property in there and I haven't touched any other code, all the other code is fine if I take out that part, but when I put it in the error shows up. Please tell me what I'm doing wrong.