Calculating spin physics

Greetings all,
Without using one of the physics engine libraries, I’d like to calculate the spin of a ball bouncing off a boundary. As I understand it, the algorithm has to do with the ball’s velocity and the angle between the ball’s direction vector and the boundary vector and the ball’s current spin. If the ball has spin, how does that affect the bounce? I’m asking for help with creating that algorithm in a Processing 3 sketch. Anyone out there have a solution?
Thanks

1 Like

you mean spin as in rotating around itself…?

Yes. A ball rotating around it’s own center

I have to admit I don’t know much about spinning objects and bouncing at a interface. A quick search points to angular impulse. You should lay out a proof of concept so you can experiment. Start with the assumption of a ball as rigid body and combine it with kinematic equations. You might need to work the equations on paper first.

Here is another article to read that is relevant. This will give you a head start so I hope. Really keen to see your outcome.

Kf

1 Like

maybe it helps to read https://en.wikipedia.org/wiki/Rotation#Sports and further down this page

Idea

to be honest, I don’t think you need a physical correct spin representation. Depending on your goal of course.

E.g. when you have a ball game like breakout :

  • Instead, when you have a spin, just set a marker (left or right spin, 3 different kinds of spin speed) and fake the spin upon a reflection by adding a bit to its angle. :wink:

Chrisir

1 Like

Just to confirm, are you modelling a 3D ball, or a 2D circle?

I’d suggest that you start by creating a sketch with a ball bouncing – no spin. This will show the specifics of the context you want to compute spin within. For example, is it 2d or 3d, what kind of thing your impactor is (a wall? a polygon? another ball?) and that thing will also be moving (you said “boundary”, so I assume no?), if you are using frame independent movement, etc etc.

I’m starting with the basics. 2d bounce on a boundary. I’m using Daniel
Shiffman’s “Staying Within the Walls” steering behavior example.
Multiplying the theta by -1 gets the ship to start rotating/spinning in
the right direction. Using a modified magnitude of the velocity as the
rotation/spin speed. Each boarder detection creates a new direction
vector. At this point I have an object/ship velocity and spin/turn
direction.
I’m trying to:
Maintain the spin. And apply the force of spin to the object/ship on
forward and reverse direction collisions.
Obviously pseudo physics. That’s the direction I’m headed. But I admit I
could be completely off track.
Thanks for getting back to me

2 Likes

Can you please show some Code!?

1 Like

If you mean based on this:

…then, without seeing your code at all, this might not be a good fit. That example is for steering / flocking, so the object is being turned based on where it is in space. That’s probably not a good way to model spin physics.

One other approach is for the object to receive – on impact – a one-time torque (angular force) which changes its angular velocity, which you might also gradually slow with angular deceleration.

class ball {
  PVector pos; // x, y, r
  PVector vel; // x, y, r
  PVector acc; // x, y, r
}

So every frame you add vel to pos to update the location and heading. Every frame, you add acc to vel – which is probably a fixed negative number in r – to decelerate the spin. And every bounce, you add a fixed amount to vel.r, modifying its existing spin by the torque imparted by the impact.

Related links:

This is the modified code “Staying Within the Walls” by Daniel Shiffman. It should give an idea of where I’m headed:

Vehicle v;
boolean mark = false;
float spinSpeed;
float d = 25;
float prevTheta = 0;
float spin = 0;
float curTheta;
Spin theta;
void setup() {
  surface.setResizable(true);
  surface.setLocation(displayWidth - int(width + width/20), 0);
  size(640, 360);
  v = new Vehicle(width/2, height/2);
  theta = new Spin(PI * 1.5);
  spinSpeed = radians(8);
}

void draw() {
  background(255);
  stroke(255, 0, 0);
  strokeWeight(4);
  noFill();
  rect(2, 2, width-4, height-4);
  strokeWeight(1);
  v.boundaries();
  v.update();
  v.display();
}
class Spin {
  float newTheta;
  Spin(float t_) {
    newTheta = t_;
  }
void turn() {
  if (mark) {
    if (newTheta < curTheta) {
      if (curTheta - newTheta < PI) {
        spin -= spinSpeed;        //left turn
      } else {
        spin += spinSpeed;       //right turn
      }
    } else {
      if (newTheta - curTheta > PI) {
        spin -= spinSpeed;        //left turn
      } else {
        spin += spinSpeed;        //right turn
      }
    }
  } else {
    curTheta = spin;
  }
}
}
class Vehicle {

  PVector position;
  PVector velocity;
  PVector acceleration;
  float r;
  float maxspeed;
  float maxforce;

  Vehicle(float x, float y) {
    acceleration = new PVector(0, 0);
    velocity = new PVector(3, -2);
    velocity.mult(5);
    position = new PVector(x, y);
    r = 6;
    maxspeed = 3;
    maxforce = 0.3;
  }
  void update() {
    velocity.add(acceleration);
    velocity.limit(maxspeed);
    position.add(velocity);
    acceleration.mult(0);
  }

  void boundaries() {
    PVector desired = null;
    if (position.x < d) {
      desired = new PVector(maxspeed, velocity.y);
    } else if (position.x > width -d) {
      desired = new PVector(-maxspeed, velocity.y);
    }
    if (position.y < d) {
      desired = new PVector(velocity.x, maxspeed);
    } else if (position.y > height-d) {
      desired = new PVector(velocity.x, -maxspeed);
    }
    if (desired != null) {
      desired.normalize();
      desired.mult(maxspeed);
      PVector steer = PVector.sub(desired, velocity);
      steer.limit(maxforce);
      applyForce(steer);
      theta = new Spin(steer.heading() * -1);
    //spinSpeed = velocity.mag()/10;  //tried to use velocity magnitude for torque
      mark=true;
    }
  }  

  void applyForce(PVector force) {
    acceleration.add(force);
  }

  void display() {
    fill(127);
    stroke(0);
    pushMatrix();
    translate(position.x, position.y);
    theta.turn();
    rotate(spin);
    circle(0, 0, r*5);
    line(0, -r*2, 0, r*2);
    popMatrix();
  }
}

Ok my previous code was close, but Daniel Shiffman came through again. I hacked together the codes from Daniel’s book “The Nature of Code” chapter 6 example 3 “Staying Within the walls”, and chapter 3 example 2 “Forces Angular Motion”; with a few minor changes. The code needs tweaking but seems to simulate the physics of a bounce. Check it out. Thanks yet again Daniel!

Vehicle v;
boolean mark = false;
float spinSpeed;
float d = 25;
float prevTheta = 0;
float spin = 0;
float curTheta;
void setup() {
  surface.setResizable(true);
  surface.setLocation(displayWidth - int(width + width/20), 0);
  size(640, 360);
  v = new Vehicle(width/2, height/2);
  spinSpeed = radians(8);
}

void draw() {
  background(255);
  stroke(255, 0, 0);
  strokeWeight(4);
  noFill();
  rect(2, 2, width-4, height-4);
  strokeWeight(1);
  v.boundaries();
  v.update();
  v.display();
}
class Vehicle {

  PVector position;
  PVector velocity;
  PVector acceleration;
  float r;
  float maxspeed;
  float maxforce;
  float angle = 0;
  float aVelocity = 0;
  float aAcceleration = 0;

  Vehicle(float x, float y) {
    acceleration = new PVector(0, 0);
    velocity = new PVector(3, -2);
    velocity.mult(5);
    position = new PVector(x, y);
    r = 6;
    maxspeed = 3;
    maxforce = 0.3;
  }
  void update() {
    velocity.add(acceleration);
    velocity.limit(maxspeed);
    position.add(velocity);

    aAcceleration = acceleration.x / 2.0;
    aVelocity += aAcceleration;
    aVelocity = constrain(aVelocity,-0.15,0.15);
    angle += aVelocity;
    acceleration.mult(0);
  }

  void boundaries() {
    PVector desired = null;
    if (position.x < d) {
      desired = new PVector(maxspeed, velocity.y);
    } else if (position.x > width -d) {
      desired = new PVector(-maxspeed, velocity.y);
    }
    if (position.y < d) {
      desired = new PVector(velocity.x, maxspeed);
    } else if (position.y > height-d) {
      desired = new PVector(velocity.x, -maxspeed);
    }
    if (desired != null) {
      desired.normalize();
      desired.mult(maxspeed);
      PVector steer = PVector.sub(desired, velocity);
      steer.limit(maxforce);
      applyForce(steer);
      mark=true;
    }
  }  

  void applyForce(PVector force) {
    acceleration.add(force);
  }

  void display() {
    fill(127);
    stroke(0);
    pushMatrix();
    translate(position.x, position.y);
    rotate(angle);
    circle(0, 0, r*5);
    line(0, -r*2, 0, r*2);
    popMatrix();
  }
}