Making a ball rotate in the direction it is moving

I’m creating a very simple physics model for a ball on a 2D soccer field. The field lies in the x-z plane.

The intitial setup

// this will be translated
this.ballPivot = new THREE.Group();

// while this is rotated inside the pivot
this.ball = (LOAD BALL MESH HERE)

this.ballPivot.add( this.ball )

scene.add( this.ballPivot );

The ball is given an initial momentum of 1, which is then split into x and z components based on the angle, like so:

    // ball initial velocity ( just set to 1 here for simplicity )
    const initialVelocity = 1;

    // split this into x and z components based on initial angle
    const xVel = Math.cos( angle ) * initialVelocity;
    const zVel = Math.sin( angle ) * initialVelocity;

    this.moveBall( xVel, zVel );

Now, I want the ball to rotate correctly in the direction it is moving, so I have set up a rotation axis like so:

    const axis = new THREE.Vector3();

    // axis orthogonal to forward vector
    axis.set( xVel, 0, zVel ).normalize();
    axis.cross( THREE.Object3D.DefaultUp );

Next, I translate the ball by the x and z velocities, reduce them slightly and rotate the ball by the correct amount so that it looks like it is rolling while moving

      self.ballPivot.translateX( xVel );
      self.ballPivot.translateZ( zVel );

      // reduce the velocity gradually to simulate friction
      xVel *= 0.99166; 
      zVel *= 0.99166;

      const totalVelocity = Math.sqrt( xVel * xVel + zVel * zVel );
      // radius of ball = 10
      const angle = -totalVelocity / ( Math.PI * 10 ) * Math.PI;

      self.ballMesh.rotateOnAxis( axis, angle );

     // stop rolling if totalVelocity is less than < 0.001 (code omitted)

So far so good. However I am also bouncing the ball, so if it hits the top of the field the zVel is negated, if it hits the front of the field the xVel is negated, at which point I recalculate the rotation axis

 if ( topAndBottomWallCheck ) {

        zVel *= -1;

        axis.set( xVel, 0, zVel ).normalize();
        axis.cross( THREE.Object3D.DefaultUp );


else if ( frontOrBackWalllCheck ) {

        xVel *= -1;

        axis.set( xVel, 0, zVel ).normalize();
        axis.cross( THREE.Object3D.DefaultUp );


And this is where things start to break down. The first bounce looks OK, but as the ball bounces more than once the rotation is less and less correct. So I guess my calculation

axis.set( xVel, 0, zVel ).normalize();
axis.cross( THREE.Object3D.DefaultUp );

is wrong.

Just a suggestion. I’d only use the Y axis rotation of the ballPivot as direction and only translate it along one axis like z, and rotate the ball mesh for the roll animation only on x then.

@Fyrestar that is an option - however it makes calculating the bounces more complicated. This way the bounce calculations are very simple, just reverse the direction of one velocity component, which works since the walls are all axis aligned. I’d rather not change that if I can avoid it since I have proceeded this far.

It basically woudln’t change your input velocity, you’d just need to rotateOnAxis (Y in this case) the pivot with this velocity.

OK, I’ve tested this - it looks like the calculations are simplified, but the problem is that there is a discontinuity when I bounce the ball off a wall.

If I do something like:

if ( topAndBottomWallCheck ) {

  self.ball.rotateY( Math.PI - ( 2 * angle ) );


Then the rotation in Y is instant and the ball ‘jumps’ making the bounce not smooth. I guess that’s not surprising since a real world ball doesn’t suddenly rotate 90 degrees or so every time it hits a wall.

Rotation before and after the turning point is correct though.

Yes that’s what it does. For a smooth rotation you could introduce a second target-pivot (separately, not attached to the ball or pivot) for direction and movement, copy the position of that target-pivot to the ball-pivot, and slerp the ball-pivot’s quaternion to the target-pivot’s quaternion.

OK, however at this point I fail to see how this is an improvement over my original approach.

Can you see how I can calculate the correct axis of rotation using that method?

A fiddle would be quite helpful.

1 Like

I’ll come back to this tomorrow and make one if I still can’t solve it. Thanks for your suggestions.

1 Like