3
\$\begingroup\$

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();
    }
}
\$\endgroup\$
  • \$\begingroup\$ You should step through the code and see where the NaNs are coming from. My first guess would be a degenerate quaternion (aka all 0s), but there can be other ways to get it in there. If any of the values you're passing in are NaNs, that will cause NaNs to show up in the matrix. So if position, orientation, or scale contain a NaN, so will the matrix. \$\endgroup\$ – user1118321 Oct 18 '17 at 5:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.