I have a ball that moves along a platform. The ball is characterized as a sphere that has a radius and a position. The platform basically is a rectangle consisting of two vertex triangles. Its class also stores the normal of the platform.
While moving the ball and applying the physics of gravity doesn't pose a problem, I just can't get the sphere to rotate correctly. To represent the rotation(s) I'm using Qt's QQuaternion class.
Here's my current rotation code:
QVector3D right = QVector3D::crossProduct(tile->getSurfaceNormal(), step).normalized();
QVector3D forward = QVector3D::crossProduct(right, tile->getSurfaceNormal()).normalized();
float radian = QVector3D::dotProduct((ball - position), forward) / radius;
angularRate = ((radian / interval) * 180.0f / M_PI) * right;
QQuaternion rotation(angularRate.length() * interval, angularRate);
orientation = rotation * orientation;
The orientation quaternion is initialized like this:
orientation = QQuaternion(0.0f, QVector3D(0.0f, 0.0f, 1.0f));
When drawing the ball I update the model matrix (QMatrix4x4) like this:
modelMatrix.setToIdentity();
modelMatrix.translate(position.x(), position.y(), position.z());
modelMatrix.rotate(orientation);
modelMatrix.scale(radius);
What I noticed when debugging is that the final model matrix gets NAN values in the first three columns. Is there any physical flaw in my calculation or could it have to do with the model matrix itself?
If that's important, here's the full code for updating the ball's properties:
void Ball::update(float interval) {
collision = false;
// Calculate new velocity
velocity += (MOVE_FORCE / mass * interval) * pushDirection;
velocity.setY(velocity.y() - (GRAVITY * interval));
/* Collision detection */
QVector3D normal(0.0f, 0.0f, 0.0f);
QVector3D step = interval * velocity;
QVector3D ball = position + step;
// Check all tiles for collision with ball
for (unsigned int i = 0; i < tiles->length(); i++) {
Tile *tile = tiles->at(i);
QVector<QVector3D> mainVertices = tile->getVertices();
QVector3D a1 = VectorMath::closestPointOnTriangle(ball, mainVertices[0], mainVertices[1], mainVertices[2]);
QVector3D a2 = VectorMath::closestPointOnTriangle(ball, mainVertices[2], mainVertices[3], mainVertices[0]);
float d1 = (ball - a1).length();
float d2 = (ball - a2).length();
QVector3D a = (d1 <= d2) ? a1 : a2;
QVector3D aN = a - tile->getAdjustedSurfaceNormal();
float aBallLength = (a - ball).length();
float aNormalBallLength = (aN - ball).length();
if (aBallLength <= radius || aNormalBallLength <= radius) {
QVector3D distance = (aBallLength <= aNormalBallLength) ? a - ball : aN - ball;
float l = distance.length();
QVector3D move = -((radius - l) / l) * distance;
// Rotation
QVector3D right = QVector3D::crossProduct(tile->getSurfaceNormal(), step).normalized();
QVector3D forward = QVector3D::crossProduct(right, tile->getSurfaceNormal()).normalized();
float radian = QVector3D::dotProduct((ball - position), forward) / radius;
angularRate = ((radian / interval) * 180.0f / M_PI) * right;
ball += move;
normal += move;
collision = true;
}
}
// Set new ball position
position = ball;
normal.normalize();
// Applying rebound
if (collision) {
float velocityNormal = QVector3D::dotProduct(velocity, normal);
QVector3D rebound = (-(1 + ELASTICITY) * velocityNormal) * normal;
velocity += rebound;
}
// Damping
velocity *= DAMPING;
QQuaternion rotation(angularRate.length() * interval, angularRate);
orientation = orientation * rotation;
if (position.y() < -10.0f) {
reset();
}
}
position
,orientation
, orscale
contain a NaN, so will the matrix. \$\endgroup\$