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.