3D Ball Physics

A528d11e2590c45b74a53dadde386125
0
Xcrypt 101 Nov 12, 2011 at 15:03

Hi all,

This weekend I’m trying to make a little minigame where I want to implement realistic ball physics.
However, when it comes to physics, I’m pretty much a dummie.
I know about the basics like velocity, acceleration, force, gravity, rotation, friction, etc. But that’s it.

I have made minigames in the past with ball physics, where the ball is sliding. What I want to achieve is a physics model where I can give the ability to the player to make the ball rotate in order to achieve displacement, not sliding.

However, I have no idea where to start. Could anyone help?

Thanks!

12 Replies

Please log in or register to post a reply.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Nov 12, 2011 at 17:52

If you want the ball to roll along a surface, you need it to rotate at a speed proportional to velocity, so that the circumference of the ball moves at the same speed as the ball itself. If rolling is all you need, you might just apply a rotation rate based on speed whenever in contact with a surface.

More generally, rolling occurs because friction between the ball and the surface is strong enough to prevent sliding; then the friction force together with some other force trying to make the ball move (e.g. gravity) form a torque causing it to rotate. With a general rigid-body physics system handling contact, forces and torque properly, rolling should occur from first principles rather than having to be explicitly coded in.

A528d11e2590c45b74a53dadde386125
0
Xcrypt 101 Nov 12, 2011 at 18:10

Thanks. The last link was particularly useful to me. I think I understand it better now. I understand the concepts in 2D.

However I’m having trouble on how to define my rotational motion in 3D. In 3D you can rotate to three axes. I believe in this case the movement parallel to the Z axis(close, far) is defined by a pitch rotation. However, I thought the movement parallel to the X axis(left, right) is defined by a roll rotation.

I programmed it this way, but the rolls look really weird. It is also difficult for me to visualise(mentally) the movement in 3D. Can anyone see the problem?

EDIT: Rolling is all I need for now, but once I got that straight I’ll start with torque and bouncing and stuff, and implement it properly :) But it feels like I need to understand 3D rotational motion first… I’m quite new to 3D actually

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Nov 12, 2011 at 19:54

Rotation in 3D definitely takes some time to understand. I remember that I had a hard time with it when I first started in 3D, as well, but now I have a much more intuitive grasp of it. It just takes awhile for your brain to wire up the rotation neurons, I guess. :)

Note that you can rotate around any axis. Not just X, Y, Z: you can take any unit vector and rotate around the axis formed by it (google “axis-angle rotation matrix” for the formula). Any rotation at all (including any sequence of rotations composed together) can be represented as an axis to rotate around and an angle to rotate by. It can also be represented as three rotations around X, Y, and Z composed together; the latter method is called Euler angles. Euler angles are what you generally see in 3D modelling apps, and correspond to an airplane’s roll, pitch, and yaw. (Note that which axis is roll, which is pitch etc. is dependent on whether you use Y-up or Z-up coordinates, and which direction your object is facing in its local space. There are various conventions out there about this. One common one is to use Z-up, and model the object facing along the +X axis; then X-rotation is roll, Y-rotation is pitch, and Z-rotation is yaw. But there are other ways to do it, and different programs / authors / engines sometimes make different assumptions.)

For rolling a ball along a surface in 3D, you would want to rotate around an axis that’s perpendicular to the ball’s path, and parallel to the surface on which it’s rolling; so one way to calculate that would be as the cross product of the ball’s velocity and the normal of the surface it’s on.

A528d11e2590c45b74a53dadde386125
0
Xcrypt 101 Nov 12, 2011 at 21:16

But that way I would be able to rotate the ball in one direction? (along the axis perpendicular to path and parallel to surface). Is there no way to ‘separate’ this? For example with movement you can separate the vector (0,1,1) into vector (0,0, 1) and vector (0,1,0) and add them together. (Sort of like the Euler angles I think, but they don’t seem to work in this particular problem).

I say this because I want to give the player control over the angular acceleration in multiple directions (arrow buttons). It should be defined in such a way that the player presses up/down the ball moves far/close. Left/right should be Left/Right. These directions should be relative to world space, not the ball’s path. I am seriously confused right now :p

Happen to know any good tutorials on this particular aspect?

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Nov 12, 2011 at 21:25

You can give the player control over the acceleration in multiple dimensions, but I think the way I’d do it is to let them control the linear acceleration, where you can separate components in the usual way. Update the ball’s velocity from these accelerations, then each frame, apply a rotation corresponding to the current (combined) velocity, using the formula I described.

Rotations around different axes, unfortunately, do not separate and combine neatly the way vectors do. Combining rotations together isn’t commutative, for instance. Doing an X-rotation followed by a Y-rotation gives a different result than doing a Y-rotation followed by an X-rotation.

A528d11e2590c45b74a53dadde386125
0
Xcrypt 101 Nov 13, 2011 at 00:13

I hope you don’t mind I’ll post some code.

I should say that you should be cautious not to get confused by the weird naming. It’s momentarily because of the simple and fake way to calculate the physics, until I get the hang of 3D rotation.

void Ball::Tick(const InputState& krInputState)
{
    float fDTime = krInputState.GetDeltaTime();

    D3DXVECTOR3 a = D3DXVECTOR3(0.0f,0.0f,0.0f);
    if (krInputState.IsKeyDown(VK_UP)) {
        a += D3DXVECTOR3(0.0f,0.0f,1.0f);
    }
    if (krInputState.IsKeyDown(VK_DOWN)) {
        a += D3DXVECTOR3(0.0f,0.0f,-1.0f);
    }
    if (krInputState.IsKeyDown(VK_RIGHT)) {
        a += D3DXVECTOR3(1.0f,0.0f,0.0f);
    }
    if (krInputState.IsKeyDown(VK_LEFT)) {
        a += D3DXVECTOR3(-1.0f,0.0f,0.0f);
    }
    D3DXVec3Normalize(&a,&a);

    m_AngularVelocity += a*fDTime*ACCELSPEED;
    if (m_AngularVelocity.x > SPEEDLIMIT) {
        m_AngularVelocity.x = SPEEDLIMIT;
    } else if (m_AngularVelocity.x < -SPEEDLIMIT) {
        m_AngularVelocity.x = -SPEEDLIMIT;
    }
    if (m_AngularVelocity.y > SPEEDLIMIT) {
        m_AngularVelocity.y = SPEEDLIMIT;
    } else if (m_AngularVelocity.y < -SPEEDLIMIT) {
        m_AngularVelocity.y = -SPEEDLIMIT;
    }
    if (m_AngularVelocity.z > SPEEDLIMIT) {
        m_AngularVelocity.z = SPEEDLIMIT;
    } else if(m_AngularVelocity.z < -SPEEDLIMIT) {
        m_AngularVelocity.z = -SPEEDLIMIT;
    }

    m_Angle += m_AngularVelocity*fDTime;

    D3DXVECTOR3 velocity = m_AngularVelocity * RADIUS;
    m_Pos += velocity*fDTime;

    D3DXVECTOR3 rotationAxis;
    D3DXVECTOR3 surfaceNormal(0.0f,1.0f,0.0f);
    D3DXVec3Cross(&rotationAxis,&surfaceNormal,&m_AngularVelocity);
    D3DXMATRIX matRotate;
    float length = D3DXVec3Length(&m_Angle);
    if (m_Angle.z < 0.0f) {
        length = -length;
    }
    D3DXMatrixRotationAxis(&matRotate,&rotationAxis,length);

    m_pBall->ResetWorldMatrix();
    m_pBall->MatrixMultiply(&matRotate); //matworld*=matRotate
    m_pBall->Translate(m_Pos); //matWorld*= matTranslate
}

As you can see I (think?) I handled it like you advised me to. Yet the rotation is still really weird. When the velocity in any dimension changes sense, it starts going mad. I suppose this has something to do with the cross product suddenly becoming inverted too, but I have no idea how to fix it.
I tried fabs(), but it still didn’t look correctly, even though movement purely along the Z axis did.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Nov 13, 2011 at 02:29

Well, the accumulation of the angle variable is wrong. You wouldn’t keep an angle variable at all, but rather keep a current rotation and apply a new rotation to it each frame based on how far the ball has rolled in this frame. You can maintain the current rotation in the form of a matrix, although later on, when you have more experience, a quaternion is better. (If a matrix is used, the matrix must from time to time be orthonormalized to keep numerical error from building up. With a quaternion you only need to normalize it - this is one of the reasons quaternions are considered better for rotations.)

The naming of the “angular velocity” variable is incorrect as it’s just a scaled version of linear velocity, but I suppose you know that. :)

Here is what I have in mind (psuedocode):

// init
curRotationMatrix = identity;

// update
acceleration = ...blah blah...
velocity += acceleration * fDTime;
m_Pos += velocity * fDTime;

rotationAxis = normalize(cross(surfaceNormal, velocity));
thisFrameAngleChange = length(velocity) / radius * fDTime;
thisFrameRotation = rotationMatrix(rotationAxis, thisFrameAngleChange)
curRotationMatrix *= thisFrameRotation;
orthonormalize(curRotationMatrix);

You can leave out that ‘orthonormalize’ part for the time being since it’s tricky and you’ll want to get the rest working. However, without that, you’ll see errors build up after you’ve been rolling the ball around for awhile; the ball might start to take on a skewed shape or something because its matrix is no longer a pure rotation. The orthonormalize brings it back to a pure rotation.

A528d11e2590c45b74a53dadde386125
0
Xcrypt 101 Nov 13, 2011 at 10:46

Thanks Reedbeta, it works \^.\^

Is Quaternions usually how it’s done then in 3D apps? I might as well go and learn that now.

EDIT: also, why is the matrix no longer a pure rotation? I didn’t see any deformation when I ran my app without orthonormalizing the matrix

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Nov 13, 2011 at 17:37

It happens because of roundoff error. In theory the composition of many rotations would still be a rotation, but in practice every matrix is slightly inexact due to the limitations of floating-point precision, and in situations like this the inaccuracy can build up over time. If you didn’t see that happening it’s possible you just didn’t run it for long enough, or you got lucky and have a very well-conditioned system. :)

67c19e6169435e69011d617cbdc71686
0
scarsia 101 Nov 22, 2011 at 00:50

ive been looking codes for this kind of game..thanks much for sharing…

Ea52b4dc64a1e292fa9d17acdf7afad2
0
Klatten 101 Dec 13, 2011 at 07:54

hi
I’m really struggling to get a strong grasp on how I should be handling collision response in a game engine I’m building around a 3D ball physics concept. Think Monkey Ball as an example of the type of gameplay.

I am currently using sphere-to-sphere broad phase, then AABB to OBB testing (the final test I am using right now is one that checks if one of the 8 OBB points crosses the planes of the object it is testing against). This seems to work pretty well, and I am getting back:

Plane that object is colliding against (with a point on the plane, the plane’s normal, and the exact point of intersection.

I’ve tried what feels like dozens of different high-level strategies for handling these collisions, without any real success. I think my biggest problem is understanding how to handle collisions against walls in the x-y axes (left/right, front/back), which I want to have elasticity, and the ground (z-axis) where I want an elastic reaction if the ball drops down, but then for it to eventually normalize and be kept “on the ground” (not go into the ground, but also not continue bouncing). Without kluging something together, I’m positive there is a good way to handle this, my theories just aren’t getting me all the way there.

For physics modeling and movement, I am trying to use a Euler based setup with each object maintaining a position (and destination position prior to collision detection), a velocity (which is added onto the position to determine the destination position), and an acceleration (which I use to store any player input being put on the ball, as well as gravity in the z coord).

Starting from when I detect a collision, what is a good way to approach the response to get the expected behavior in all cases?

Thanks in advance to anyone taking the time to assist… I am grateful for any pointers, and happy to post any additional info or code if it is useful.