Problem about creating water waves when using mass spring damper system

I got a problem when trying to make water waves.I only got one jumping surfacepoint on a still water surface.
Here is the code.

lake lake;
void setup()
{
  size(400, 500);
  lake = new lake();
}
void draw()
{
  background(255);
 lake.run();

}
class lake{
  water surfacePoints[];
  int num = width;
  PVector position;
  lake(){
    surfacePoints = new water[num];
    for (int i = 0; i < surfacePoints.length; i++)
  {
    surfacePoints[i] = new water(1,0.1,0.2,new PVector(i,height/2));
  }
  }
  
void run(){
  //surfacePoints[0].update();
  //surfacePoints[0].display();
  for (int i = 1; i < surfacePoints.length - 1; i++)
  {
    
    
  surfacePoints[i].neighbourForce(surfacePoints[i-1]);
  surfacePoints[i].neighbourForce(surfacePoints[i+1]);
  surfacePoints[i].update();
  surfacePoints[i].display();
   noStroke();
    fill(59, 180, 250);
    beginShape(QUAD);
        vertex(surfacePoints[i].position.x, height);
        vertex(surfacePoints[i].position.x, surfacePoints[i].position.y);
        vertex(surfacePoints[i].position.x+1, surfacePoints[i+1].position.y);
        vertex(surfacePoints[i].position.x+1, height);
        endShape(CLOSE);
  }
  //surfacePoints[num].update();
  //surfacePoints[num].display();
 
  surfacePoints[100].updateForce(2);
  
}



  
  }
class water{
  float mass, springConstant, damping;
  float positionchange,velocity, acceleration, force;
  PVector position, origin;
  water(float mass, float springConstant, float damping, PVector origin)
  {
    this.mass = mass;
    this.springConstant = springConstant;
    this.damping = damping;
    this.origin = origin;
    this.position = new PVector();
  }
  void updateForce(float _force)
  {
    force = _force - (velocity * damping) - (positionchange * springConstant);
    acceleration = force/mass;
    velocity += acceleration;
    positionchange += velocity;
  }
  void update()
  {
    acceleration = springConstant*positionchange +damping*velocity;
    acceleration = acceleration/mass;
    velocity += acceleration;
    positionchange += velocity;
  }
  void display()
  {
    this.position.set(0, positionchange);
    this.position.add(origin);
   
  }
  void neighbourForce(water neighbour){
    float displacement = neighbour.position.y-position.y;
    
    force += displacement*springConstant*0.01;
    
    
  
}
}

eddited:
Sorry for the bad format.


This is what I want to achieve finally.When a surface point is added force,the neighbours receive spring force.Each surfacepoint has damping effect and the result looks like waves.
My problem is that it seems I cannot pass the force through neighbours.

1 Like

Please format all of your code. You can do this by highlighting it all in the editor, and then tapping the ‘code’ format button </>

In addition to this, can I ask you to provide some more details? For example, what is the intended behavior? Have you isolated the problem to a specific method? What errors, if any, were thrown.

The more information we get, the better we can help you.

All that said, are your initializations all correct in the Lake constructor?

class lake{
water surfacePoints[];
int num = width;
float giftX = 100;
PVector position;
lake(){
surfacePoints = new water[num];
for (int i = 0; i &lt; surfacePoints.length; i++)
{
surfacePoints[i] = new water(1,0.1,0.2,new PVector(i,height/2));
}
1 Like

Hi,

As @tony said, please format your code. Don’t forget to hit ctrl+t in processing IDE to properly indent it.

At the moment we can’t even run the code because there are some typos on this line:

acceleration = springConstantpositionchange +dampingvelocity;

@tony also said it, but I really want to insist on the fact that we lack of context to really be able to help you. It is clear to you of what you are trying to achieve but far from obvious to us.

Come back with more context and we’ll do our best to help :slight_smile:

Can you add some comments to your water class?

I think your problem could be this in your constructor:

this.origin = origin;
this.position = new PVector();

it seems that position is not been properly updated in your engine. Also, I wouldnt use quads for drawing the water. Instead, draw vertex as contiguos points and you need to add two extra points, the bottom left and bottom right corner of your lake.

Kf

Hi @zzz.mcw,

Be careful when you edit a post that is not the last: there is no notification so other users won’t notice any change. It is a bit by luck that I came back here. (Now at least it will be up the pile :slight_smile:)

Thank you for explaining your problem in a more detail manner.

I don’t have the time to properly get into it right now but it seems that you have a problem with your initial state. I modified your code so it will run one frame of animation every time you press your mouse. You can see that the first frame is a bit weird.

Even if it is not the solution at least it allows you to see how your code behave and maybe understand a bit more what is going on!

I think you need to implement an applyForce() in your water class to launch the animation. You start with a flat lake, then you apply a force to one of the water and then you watch it moves.

The problem with setting an initial state that is not flat and not anitiating the movement with a force is that you don’t know if this is “physically” accurate in your model and thus it can lead to some weird behaviors. For example, if you set the first half of your lake to a height of x + 20 and the second half at a height of x, you know that you can’t expect that, your model will never give you this kind of results and it will probably not work the way you expect it.

lake lake;
boolean play;


void setup() {
  size(400, 500);
  lake = new lake();
  play = false;
}


void draw() {
  if (play) {
    background(255);
    lake.run();
    play = false;
  }
}


class lake {
  
  water surfacePoints[];
  int num = width;
  PVector position;
  
  
  lake() {
    surfacePoints = new water[num];
    for (int i = 0; i < surfacePoints.length; i++)
    {
      surfacePoints[i] = new water(1, 0.1, 0.2, new PVector(i, height/2));
    }
  }


  void run() {
    //surfacePoints[0].update();
    //surfacePoints[0].display();
    for (int i = 1; i < surfacePoints.length - 1; i++)
    {


      surfacePoints[i].neighbourForce(surfacePoints[i-1]);
      surfacePoints[i].neighbourForce(surfacePoints[i+1]);
      surfacePoints[i].update();
      surfacePoints[i].display();
      noStroke();
      fill(59, 180, 250);
      beginShape(QUAD);
      vertex(surfacePoints[i].position.x, height);
      vertex(surfacePoints[i].position.x, surfacePoints[i].position.y);
      vertex(surfacePoints[i].position.x+1, surfacePoints[i+1].position.y);
      vertex(surfacePoints[i].position.x+1, height);
      endShape(CLOSE);
    }
    //surfacePoints[num].update();
    //surfacePoints[num].display();

    surfacePoints[100].updateForce(2);
  }
}



class water {
  float mass, springConstant, damping;
  float positionchange, velocity, acceleration, force;
  PVector position, origin;


  water(float mass, float springConstant, float damping, PVector origin)
  {
    this.mass = mass;
    this.springConstant = springConstant;
    this.damping = damping;
    this.origin = origin;
    this.position = new PVector();
  }


  void updateForce(float _force)
  {
    force = _force - (velocity * damping) - (positionchange * springConstant);
    acceleration = force/mass;
    velocity += acceleration;
    positionchange += velocity;
  }


  void update()
  {
    acceleration = springConstant*positionchange +damping*velocity;
    acceleration = acceleration/mass;
    velocity += acceleration;
    positionchange += velocity;
  }


  void display()
  {
    this.position.set(0, positionchange);
    this.position.add(origin);
  }


  void neighbourForce(water neighbour) {
    float displacement = neighbour.position.y-position.y;

    force += displacement*springConstant*0.01;
  }
}



void mousePressed() {
  play = true;
}

Hopefully, now your post is visible, other users will be able to help you more.

1 Like

Two of several ways of approaching this problem (the end goal)

  1. Use a water class that distributes forces – this is your code approach, it needs debugging
  2. Use a general purpose physics library – e.g. 2D physics – and write your spring line using that.

For the second approach, see the Simulation section of the Processing Libraries page:

https://processing.org/reference/libraries/

In particular, check out Box2D – and its tutorials and online videos.

I think this is the sort of thing you might be trying to do -

lake lake;
void setup()
{
  size(400, 500);
  lake = new lake();
}
void draw()
{
  background(255);
  lake.run();
}
void keyPressed() {    
  lake.surfacePoints[100].position.y+=100;
}

class lake {
  water surfacePoints[];
  int num = width;
  PVector position;
  lake() {
    surfacePoints = new water[num];
    for (int i = 0; i < surfacePoints.length; i++)
    {
      surfacePoints[i] = new water(5, 0.6, 0.9, new PVector(i, height/2), new PVector(i, height/2));
    }
  }

  void run() {

    for (int i = 1; i < surfacePoints.length - 1; i++)
    {
      surfacePoints[i].update(surfacePoints[i+1]);
      surfacePoints[i].update(surfacePoints[i-1]);
      surfacePoints[i].display();
    }
  }
} 

class water {
  float mass, springConstant, damping;
  float velocity, acceleration;
  PVector position, origin;

  water(float mass, float springConstant, float damping, PVector position, PVector origin)
  {
    this.mass = mass;
    this.springConstant = springConstant;
    this.damping = damping;
    this.position = position;
    this.origin = origin;
  }

  void update(water neighbour)
  {
    float displacement = neighbour.position.y-position.y;
    float force = displacement + (origin.y - position.y) * springConstant;
    acceleration = force/mass;
    velocity = damping * (velocity + acceleration);
    position.y += velocity;
  }
  void display()
  {    
    stroke(0, 0, 255);
    line(position.x, position.y, position.x, height);
  }
}

it works, sort of, but its not really a good way to go about simulating water.
I tried doing something very much like this, and there are some issues that aren’t really worth trying to solve.

1 Like