# Rope physics prototype 3D

**URL:** <https://discourse.processing.org/t/rope-physics-prototype-3d/7021>\
**Category:** Gallery\
**Created:** [December 30, 2018, 4:03pm UTC](https://discourse.processing.org/t/rope-physics-prototype-3d/7021 "2018-12-30T16:03:17Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![BennyHacker](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/bennyhacker/32/2969_2.png) [@BennyHacker](https://discourse.processing.org/u/BennyHacker)\
**Post date:** [December 30, 2018, 4:03pm UTC](https://discourse.processing.org/t/rope-physics-prototype-3d/7021/1 "2018-12-30T16:03:17Z")

</div>

Here is an example where a 3D rope can be controlled with the mouse. Press ‘w’ to toggle wind, ‘g’ to toggle gravity, space to pause and mouse wheel to increase/decrease wind strength. Boxes can be spawned by pressing ‘1’. I should also mention that none of the objects collide with each other.

```auto
ArrayList<Spring> springs;
PVector grab, grabVel;
PVector wind;
boolean selected=false;
boolean pause = false;
boolean windOn = false;
boolean gravityOn = true;
float windStrength = 10;
float num = 10;
Spring chain;
void setup() {
  size(400, 400, P3D);
  springs = new ArrayList<Spring>();
  chain = new Spring(new PVector(), new PVector());
  chain.len=6;
  springs.add(chain);
  for(int i = 0; i < 8; i++){
  Spring newChain = new Spring(springs.get(springs.size()-1).v2,new PVector());
  newChain.vel1=springs.get(springs.size()-1).vel2;
  newChain.d1=true;
  newChain.len=6;
  springs.add(newChain);
  }
  wind = new PVector();
}
void draw() {
  noCursor();
  //add random wind
  wind.mult(.99);
  PVector p = PVector.random3D();
  p.mult(.1);
  wind.add(p);
  background(255);
  lights();
  for (int i = 0; i < springs.size(); i++) {
    if(!pause){
    springs.get(i).update();
    }
  }
  for (int i = 0; i < springs.size(); i++) {
    springs.get(i).display();
  }
  chain.v1.x=mouseX;
  chain.v1.y=mouseY;
  chain.vel1.x+=mouseX-pmouseX;
  chain.vel1.y+=mouseY-pmouseY;
  chain.v1.z=0;
}
void keyReleased() {
  if (key==' ') {
    pause=!pause;
  }
  if (key=='1') {
    makeBox(new PVector(mouseX, mouseY, random(-100, 100)));
  }
  if (key=='g'||key=='G') {
    gravityOn=!gravityOn;
  }
  if (key=='w'||key=='W') {
    windOn=!windOn;
  }
}
void mouseWheel(MouseEvent event) {
  float e = event.getCount();
  windStrength-=e;
  if (windStrength<1) {
    windStrength=1;
  }
}
class Spring {
  PVector v1, v2;
  PVector vel1, vel2;
  float len = num*3;
  float damp = 1;
  float groundFriction = .34;
  float tightness = 1;
  boolean d1, d2;
  Spring(PVector V1, PVector V2) {
    v1 = V1;
    v2 = V2;
    vel1 = new PVector();
    vel2 = new PVector();
    d1 = false;
    d2 = false;
  }
  void update() {
    PVector w = wind.copy();
    w.mult((windStrength*4)/100);
    //since two springs can share the same PVector
    //we need to 'deactivate' one of them to prevent
    //double updating where we don't want it
    if (!d1) {
      if (gravityOn)vel1.y+=.34;
      if (windOn)vel1.add(w);
      vel1.mult(.9);
      v1.add(vel1);
    }

    if (!d2) {
      if (gravityOn)vel2.y+=.34;
      if (windOn)vel2.add(w);
      vel2.mult(.9);
      v2.add(vel2);
    }

    //spring math
    float ex = len-dist(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z)*.5;
    PVector dir = v2.copy();
    dir.sub(v1);
    dir.normalize();
    dir.mult(ex);
    v1.sub(PVector.mult(dir, tightness));
    v2.add(PVector.mult(dir, tightness));
    vel1.sub(PVector.mult(dir, damp));
    vel2.add(PVector.mult(dir, damp));
  }
  void display() {
    if (v1.y>height-25) {
      v1.y=height-25;
      vel1.mult(groundFriction);
    }
    if (v2.y>height-25) {
      v2.y=height-25;
    }
    if (v1.x>width) {
      v1.x=width;
    }
    if (v2.x>width) {
      v2.x=width;
    }
    if (v1.x<0) {
      v1.x=0;
    }
    if (v2.x<0) {
      v2.x=0;
    }
    fill(255, 0, 0);
    noStroke();
    if (!d1) {
      pushMatrix();
      translate(v1.x, v1.y, v1.z);
      sphere(4);
      popMatrix();
    }
    if (!d2) {
      pushMatrix();
      translate(v2.x, v2.y, v2.z);
      sphere(4);
      popMatrix();
    }
    stroke(0);
    line(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z);
  }
}
void connectSpring(PVector p1, PVector v1, PVector p2, PVector v2) {
  Spring spr = new Spring(p1, p2);
  spr.vel2=v2;
  spr.vel1=v1;
  spr.d1=true; //deactivates some properties
  spr.d2=true; //deactivates some properties
  springs.add(spr);
}
void connectSpring(PVector p, PVector v) {
  Spring spr = new Spring(new PVector(mouseX, mouseY), p);
  spr.vel2=v;
  spr.d2=true; //deactivates some properties
  springs.add(spr);
}
void makeBox(PVector pos) {
  num=10;
  PVector p1 = new PVector(pos.x-30, pos.y-30, pos.z-30);
  PVector p2 = new PVector(pos.x+30, pos.y-30, pos.z-30);
  PVector p3 = new PVector(pos.x-30, pos.y+30, pos.z-30);
  PVector p4 = new PVector(pos.x+30, pos.y+30, pos.z-30);
  PVector p5 = new PVector(pos.x-30, pos.y-30, pos.z+30);
  PVector p6 = new PVector(pos.x+30, pos.y-30, pos.z+30);
  PVector p7 = new PVector(pos.x-30, pos.y+30, pos.z+30);
  PVector p8 = new PVector(pos.x+30, pos.y+30, pos.z+30);
  //for edges
  Spring spr1 = new Spring(p1, p2);
  Spring spr2 = new Spring(p3, p4);
  Spring spr3 = new Spring(p5, p6);
  Spring spr4 = new Spring(p7, p8);
  springs.add(spr1);
  springs.add(spr2);
  springs.add(spr3);
  springs.add(spr4);
  connectSpring(p1, spr1.vel1, p5, spr3.vel1);
  connectSpring(p2, spr1.vel2, p6, spr3.vel2);
  connectSpring(p3, spr2.vel1, p7, spr4.vel1);
  connectSpring(p4, spr2.vel2, p8, spr4.vel2);
  connectSpring(p1, spr1.vel1, p3, spr2.vel1);
  connectSpring(p2, spr1.vel2, p4, spr2.vel2);
  connectSpring(p5, spr3.vel1, p7, spr4.vel1);
  connectSpring(p6, spr3.vel2, p8, spr4.vel2);
  num=sqrt(2)*10; 
  // for faces
  connectSpring(p1, spr1.vel1, p6, spr3.vel2);
  connectSpring(p2, spr1.vel2, p5, spr3.vel1);
  connectSpring(p3, spr2.vel1, p8, spr4.vel2);
  connectSpring(p4, spr2.vel2, p7, spr4.vel1);
  connectSpring(p1, spr1.vel1, p7, spr4.vel1);
  connectSpring(p5, spr3.vel1, p3, spr2.vel1);
  connectSpring(p2, spr1.vel2, p8, spr4.vel2);
  connectSpring(p6, spr4.vel2, p4, spr2.vel2);
  connectSpring(p1, spr1.vel1, p4, spr2.vel2);
  connectSpring(p2, spr1.vel2, p3, spr2.vel1);
  connectSpring(p5, spr3.vel1, p8, spr4.vel2);
  connectSpring(p6, spr3.vel2, p7, spr4.vel1);
  num=sqrt(3)*10;
  //for diagonal support
  connectSpring(p1, spr1.vel1, p8, spr4.vel2);
  connectSpring(p2, spr1.vel2, p7, spr4.vel1);
  connectSpring(p5, spr3.vel1, p4, spr2.vel2);
  connectSpring(p6, spr3.vel2, p3, spr2.vel1);
}

```

Here is the relevant bit of code for the rope physics where I’ve set _damp_ equal to .24 and _tightness_ equal to .46 and springLength can be any positive number.

```auto
//spring math
    float ex = springLength-dist(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z)*.5;
    PVector dir = v2.copy();
    dir.sub(v1);
    dir.normalize();
    dir.mult(ex);
    v1.sub(PVector.mult(dir, .46));
    v2.add(PVector.mult(dir, .46));
    vel1.sub(PVector.mult(dir, .24));
    vel2.add(PVector.mult(dir, .24));

```

Edit: It’s also important to understand how connecting Springs work. For example:

Connecting Springs spr\_1 and spr\_2 would require setting spr\_2.v1 = spr\_1.v2 and similarly spr\_2.vel1 = spr\_1.vel2.

Make sure to ‘deactivate’ one of the connected springs. For example, if you connected spr\_2.v1 and spr\_1.v2, you should either set spr\_2.d1 = true OR spr\_1.d2 = true

The math isn’t spot on so any feedback would be appreciated!

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [December 30, 2018, 6:11pm UTC](https://discourse.processing.org/t/rope-physics-prototype-3d/7021/2 "2018-12-30T18:11:07Z")

</div>

Impressive.

when you use

```auto
      fill(255, 0, 0); 
      noStroke();

```

in both places for your spheres, they look better

Use `lights();` after background() in draw()

Use ctrl-t to auto format your code (indents)

Thanks for sharing!

Chrisir

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [December 30, 2018, 6:50pm UTC](https://discourse.processing.org/t/rope-physics-prototype-3d/7021/3 "2018-12-30T18:50:28Z")

</div>

Also when pressing ‘1’ the Z is missing.

I changed it to -1100

```auto
 if (key=='1') {
    makeBox(new PVector(mouseX, mouseY, random(-1100, 100)));
  }

```

and

removed 2 lines that were killing Z for me

```auto
  Spring(PVector V1, PVector V2) {
    v1 = V1;
    v2 = V2;
    //v1.z=random(-5, 5);
    //v2.z=random(-5, 5);

```

---

<div class="post-metadata">

**Author:** ![BennyHacker](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/bennyhacker/32/2969_2.png) [@BennyHacker](https://discourse.processing.org/u/BennyHacker)\
**Post date:** [December 30, 2018, 7:08pm UTC](https://discourse.processing.org/t/rope-physics-prototype-3d/7021/4 "2018-12-30T19:08:31Z")

</div>

Ah, I forgot to move that part. Works a lot nicer now. Thanks for the feedback, Chrisir

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [December 31, 2018, 10:39am UTC](https://discourse.processing.org/t/rope-physics-prototype-3d/7021/5 "2018-12-31T10:39:47Z")

</div>

**Also** when the cubes hit the floor they should be marked as unmoving so the wind does not affect them anymore.

---

<div class="post-metadata">

**Author:** ![BennyHacker](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/bennyhacker/32/2969_2.png) [@BennyHacker](https://discourse.processing.org/u/BennyHacker)\
**Post date:** [January 1, 2019, 2:25pm UTC](https://discourse.processing.org/t/rope-physics-prototype-3d/7021/6 "2019-01-01T14:25:18Z")

</div>

Based on your suggestion I’ve updated the code so that there’s now a ground friction coefficient, which slows grounded cubes a bit but still allows movement. I’ve also made the initial rope length more adjustable and fixed it’s weird weight problems (no offense to the rope)
