Dry Rolling Friction

beijingrocks

16-09-2006 15:57:14

Hi, I'm fairly new to Ogre after dabbling with Irrlicht a bit and I'm also fairly new to C++ in general, but I feel as though I'm progressing at a decent pace.

Firstly, I'd like to congratulate Walaber on this great wrapper for Newton Game Dynamics - a little bit of flattery never hurt right?

Anyway, I'm working on a pool game and became aware I needed to implement a custom joint that could take care of dry rolling friction, as this is a pretty major part of the physics behind Pool and other ball games, such as bowling or golf, etc.

In the Newton SDK there is custom joint specifically for dry rolling friction, but so far this custom joint does not seem to have been implemented in OgreNewt. Here is Julio's source file for the joint from the Newton SDK:


CustomDryRollingFriction::CustomDryRollingFriction(NewtonBody* child, dFloat radius, dFloat coeficient)
:NewtonCustomJoint(1, child, NULL)
{
dFloat mass;
dFloat Ixx;
dFloat Iyy;
dFloat Izz;

NewtonBodyGetMassMatrix (child, &mass, &Ixx, &Iyy, &Izz);

m_frictionCoef = coeficient;
m_frictionTorque = Ixx * radius;
}


CustomDryRollingFriction::~CustomDryRollingFriction()
{
}


// rolling friction works as follow: the idealization of the contact of a spherical object
// with a another surface is a point that pass by the center of the sphere.
// in most cases this is enough to model the collision but in insufficient for modeling
// the rolling friction. In reality contact with the sphere with the other surface is not
// a point but a contact patch. A contact patch has the property the it generates a fix
// constant rolling torque that opposes the movement of the sphere.
// we can model this torque by adding a clamped torque aligned to the instantaneously axis
// of rotation of the ball. and with a magnitude of the stopping angular acceleration.
void CustomDryRollingFriction::SubmitConstrainst ()
{
dVector omega;
dFloat time;
dFloat omegaMag;
dFloat torqueFriction;

// get the omega vector
NewtonBodyGetOmega(m_body0, &omega[0]);

omegaMag = dSqrt (omega % omega);
if (omegaMag > 0.1f) {
// tell newton to used this the friction of the omega vector to apply the rolling friction
dVector pin (omega.Scale (1.0f / omegaMag));
NewtonUserJointAddAngularRow (m_joint, 0.0f, &pin[0]);

// calculate the acceleration to stop the ball in one time step
time = NewtonGetTimeStep (m_world);
NewtonUserJointSetRowAcceleration (m_joint, -omegaMag / time);

// set the friction limit proportional the sphere Inertia
torqueFriction = m_frictionTorque * m_frictionCoef;
NewtonUserJointSetRowMinimumFriction (m_joint, -torqueFriction);
NewtonUserJointSetRowMaximumFriction (m_joint, torqueFriction);

} else {
// when omega is too low sheath a little bit and damp the omega directly
omega = omega.Scale (0.2f);
NewtonBodySetOmega(m_body0, &omega[0]);
}
}


Now first off, I assume there are no problems using this code and editing it for use in OgreNewt(right?), as the .cpp and .h for custom joints are included as is in the Newton SDK.

There are quite a few obvious conversions (dFloat's to Real's and dVector's to Vector3's - or have I misunderstood these variables from Newton?). All the methods can also be easily converted to OgreNewt's equivalents as well.

The one line that threw me a bit was:

omegaMag = dSqrt (omega % omega);


Although I'm aware of the modulo operator's uses with int's, I don't quite understand it's operation between 2 dVectors here. However, as the var is called omegaMag, I guess the magnitude of the omega vector should be found, by rooting it's squared length.

Also, the last line directly changes the omega value of the ball, which isn't possible using OgreNewt, as the inherited "m_Body0" is a const pointer. Could this be easily overcome by passing in a pointer to the OgreNewt Body?

Any help or advice would be much appreciated.

raven_coda

19-07-2007 00:21:01

Has anything every happened with this, would it be too much to ask to add this to the prebuilt custom made joints? I've just ran into a situation where I'd need it. I'll try my hand at porting it but I'm not too familar with Ogre yet...

walaber

19-07-2007 01:16:10

basically you need to re-implement Julio's code in a class that inherits from OgreNewt::CustomJoint. Have a look at the custom joint demo if you need an example...

it should be pretty straightforward... I don't really have the time to create and test it right now, but I can help out if someone get the "ball rolling" (sorry, couldn't resist)... :)

raven_coda

19-07-2007 03:49:59

Works Like a charm!!!

Will you add this to the next release of OgreNewt?

rollingFrictionjoint.h
#pragma once
/*
This is the implementation of a 'dry Rolling Friction' joint, created as a custom joint
*/

#include <OgreNewt.h>

namespace OgreNewt
{
namespace PrebuiltCustomJoints
{
class RollingFrictionJoint : public OgreNewt::CustomJoint
{
public:

// constructor - should be implemented by the user.
RollingFrictionJoint( OgreNewt::Body* child, Ogre::Real radius, Ogre::Real coeficient);

~RollingFrictionJoint();

// also user MUST implement this function to actually apply the constraint.
void submitConstraint();

private:

Ogre::Real m_frictionCoef;
Ogre::Real m_frictionTorque;

};
}
}




rollingFrictionJoint.cpp
#include "RollingFrictionJoint.h"

// cunstructor. we must pass the 2 bodies (2nd can be NULL), also the max DOF for the joint, up to 6.
OgreNewt::PrebuiltCustomJoints::RollingFrictionJoint::RollingFrictionJoint(OgreNewt::Body *child, Ogre::Real radius, Ogre::Real coeficient)
:OgreNewt::CustomJoint( 2, child, NULL )
{
Ogre::Real mass;
Ogre::Vector3 inertia;

child->getMassMatrix(mass, inertia);

m_frictionCoef = coeficient;
m_frictionTorque = inertia.x * radius;

}


OgreNewt::PrebuiltCustomJoints::RollingFrictionJoint::~RollingFrictionJoint()
{
}

// the important function that applies the joint.
void OgreNewt::PrebuiltCustomJoints::RollingFrictionJoint::submitConstraint()
{
Ogre::Vector3 omega;
Ogre::Real time;
Ogre::Real omegaMag;
Ogre::Real torqueFriction;

// get the omega vector
omega= this->m_body0->getOmega();

omegaMag = omega.length();

if (omegaMag > 0.1f)
{
// tell newton to used this the friction of the omega vector to apply the rolling friction
Ogre::Vector3 pin= (omega.normalisedCopy() * (1.0f / omegaMag));
addAngularRow(Ogre::Radian(0.0), pin);

// calculate the acceleration to stop the ball in one time step
time=m_world->getTimeStep();

setRowAcceleration(-omegaMag / time);

// set the friction limit proportional the sphere Inertia
torqueFriction = m_frictionTorque * m_frictionCoef;

setRowMinimumFriction( -torqueFriction);
setRowMaximumFriction( torqueFriction);

} else {
// when omega is too low sheath a little bit and damp the omega directly
omega = omega.normalisedCopy() * (0.2f);
((OgreNewt::Body*)this->m_body0)->setOmega(omega);
}



}