For a small C/C++ game project, I want to add some physics on a ball, to allow it to roll against the slopes of a 3d world, in the same way as the example visible in the image below:
However I have very few skills in physics, and I have some trouble to understand which physical laws should be applied, and how concepts like energy, force and acceleration should be used here. As a beginner, I imagined the situation as follow:
Where:
- N (in green) is the normal of the current polygon above the ball
- Fg (in red) is the gravitational force, which should be constant
- Ff (also in red) is the frictional force, which should be constant
- P (in blue) is the current ball position
- P' (also in blue) is the next point to calculate
I also wrote a dedicated function to calculate the physics on my ball, which is called every time a frame is about to be rendered. When this function is called, I know:
- The elapsed time
- The current ball position
- Which polygon is currently below the ball (from which I can extract the N normal shown above, and thus the slope) The constant forces (Fg and Ff shown above)
From these values I tried to calculate the next ball position (P' shown above) based on the physics law F = m * a
This gave the following code:
#define M_CSR_Gravitation 9.81f
typedef struct
{
CSR_Vector3 m_AccumulatedForce;
float m_Mass;
} CSR_Body;
typedef struct
{
CSR_Vector3 m_Position;
CSR_Sphere m_Geometry;
CSR_Body m_Body;
} CSR_Ball;
CSR_Ball g_Ball;
void csrPhysicsGravity(float mass, CSR_Vector3* pF)
{
// the formula for the gravitation is F = m * g
pF->m_X = 0.0f;
pF->m_Y = mass * M_CSR_Gravitation;
pF->m_Z = 0.0f;
}
void ApplyPhysics(float elapsedTime, CSR_Plane groundPlane, const CSR_Vector3& frictionForce)
{
float dirAngleX;
float dirAngleZ;
float velocityAngle;
CSR_Vector3 planeNormal;
CSR_Vector3 gravity;
CSR_Vector3 xDir;
CSR_Vector3 zDir;
CSR_Vector3 up;
CSR_Vector3 dropForce;
CSR_Vector3 motionForce;
CSR_Vector3 acceleration;
CSR_Vector3 prevCenter;
planeNormal.m_X = groundPlane.m_A;
planeNormal.m_Y = groundPlane.m_B;
planeNormal.m_Z = groundPlane.m_C;
// calculate the gravity force applied on the ball
csrPhysicsGravity(g_Ball.m_Body.m_Mass, &gravity);
xDir.m_X = 1.0f;
xDir.m_Y = 0.0f;
xDir.m_Z = 0.0f;
// calculate the angle to drift against the x axis
csrVec3Dot(&xDir, &planeNormal, &dirAngleX);
zDir.m_X = 0.0f;
zDir.m_Y = 0.0f;
zDir.m_Z = 1.0f;
// calculate the angle to drift against the z axis
csrVec3Dot(&zDir, &planeNormal, &dirAngleZ);
up.m_X = 0.0f;
up.m_Y = 1.0f;
up.m_Z = 0.0f;
// calculate the drift velocity (the steeper is the slope, the higher is the fall speed)
csrVec3Dot(&up, &planeNormal, &velocityAngle);
// calculate the drift offsets to apply on the next frame
dropForce.m_X = dirAngleX * velocityAngle * -gravity.m_Y;
dropForce.m_Y = 0.0f;
dropForce.m_Z = dirAngleZ * velocityAngle * -gravity.m_Y;
motionForce.m_X = g_Ball.m_Body.m_AccumulatedForce.m_X + dropForce.m_X - frictionForce.m_X;
motionForce.m_Y = g_Ball.m_Body.m_AccumulatedForce.m_Y + dropForce.m_Y - frictionForce.m_Y;
motionForce.m_Z = g_Ball.m_Body.m_AccumulatedForce.m_Z + dropForce.m_Z - frictionForce.m_Z;
g_Ball.m_Body.m_AccumulatedForce = motionForce;
acceleration.m_X = (motionForce.m_X / g_Ball.m_Body.m_Mass) * elapsedTime;
acceleration.m_Y = (motionForce.m_Y / g_Ball.m_Body.m_Mass) * elapsedTime;
acceleration.m_Z = (motionForce.m_Z / g_Ball.m_Body.m_Mass) * elapsedTime;
prevCenter = g_Ball.m_Geometry.m_Center;
g_Ball.m_Geometry.m_Center.m_X += -acceleration.m_X * elapsedTime;
g_Ball.m_Geometry.m_Center.m_Y += -acceleration.m_Y * elapsedTime;
g_Ball.m_Geometry.m_Center.m_Z += -acceleration.m_Z * elapsedTime;
}
It works very roughly. The ball actually rolls down the slope, but never stops. And if I try to throw the ball from the bottom of the slope, it accelerates instead of curbing.
Obviously something is pretty wrong, but what? As I say above, I'm not an expert in physics and I think I tend to confuse notions such acceleration, force and energy. However I tried to resolve this system by myself, without success.
So I would be thankful if somebody can explain to me:
- Which concepts of physics are involved to resolve the above mentioned system
- How should I correct my code to reach the above described objective (of course as long as the code does not have to be rewritten entirely)
- And/Or an example of a such algorithm, even if written in pseudo-code or in another programming language
IMPORTANT NOTE I know that there are many physics engines, commercial or open-source, like e.g. Bullet, Box2d or Havok, which I may use to resolve the above issue. THIS IS NOT MY OBJECTIVE, I wan't to use them, at least for now. I WANT TO LEARN AND UNDERSTAND how to resolve this issue before using such engines. And I think that the proposed problem is simple enough to serve for this purpose.