I've been searching on here for some ideas and I came across the following:
1. Store the orientation of the ball as a quaternion or matrix
2. For each update, if the speed of the ball is greater than a specified epsilon:
3. The axis of rotation is the normalized cross product of the ball's velocity vector and the current 'up' vector
4. The angle of rotation (in radians) is the distance traveled by the ball during that update divided by the ball's radius
5. Apply this axis-angle rotation to the ball's orientation
6. Re-normalize the orientation to prevent drift (normalization for quaternions, orthogonalization for matrices)[/quote]
Based on this I have created the following methods
In my Matrix class
inline void Matrix3D::SetRotation(Vector3D axis, float angle)
{
Matrix3D& matrix = *this;
float nx = axis.x;
float ny = axis.y;
float nz = axis.z;
float c = cosf(angle);
float s = fastSinf(angle);
matrix(0) = c+nx*nx*(1.0f-c);
matrix(1) = nx*ny*(1.0f-c)-nz*s;
matrix(2) = nx*nz*(1.0f-c)+ny*s;
matrix(3) = matrix(7) = matrix(11) = matrix(12) = matrix(13) = matrix(14) = 0.0f;
matrix(4) = ny*nx*(1.0f-c)+nz*s;
matrix(5) = c+ny*ny*(1.0f-c);
matrix(6) = ny*nz*(1.0f-c)-nx*s;
matrix(8) = nz*nx*(1.0f-c)-ny*s;
matrix(9) = nz*ny*(1.0f-c)+nx*s;
matrix(10) = c+nz*nz*(1.0f-c);
matrix(15) = 1.0f;
}
And my function to rotate the ball
static inline bool getBallRotationMatrix(Vector3D velocity, Vector3D up, Matrix3D& matrix)
{
Vector3D axis = Cross(velocity, up).Normalize();
float distance = sqrtf(velocity.x * velocity.x + velocity.y * velocity.y);
float angle = distance;
matrix.SetRotation(axis, angle);
return true;
}
Finally my code to apply the matrix to the model
Matrix3D matrix = Model->GetMatrix();
static Vector3D velocity = Vector3DEmpty();
velocity.x += position.x - m_lastPosition.x;
velocity.y += position.y - m_lastPosition.y;
if(getBallRotationMatrix(velocity, Vector3DMake(0, 0, 1), matrix))
Model->SetMatrix(matrix);
I have excluded the "distance traveled by the ball during that update divided by the ball's radius" part for now as I just want to have the ball roll in the direction it's moving for now.
Unfortunately it seems no different to SetRotationYawPitchRoll() in that one rotation axis seems to screw up the another.
What is wrong with my code? I don't quite understand how to "orthogonalize the matrix" at the end. Would this explain the results?