AngularVectorForce, what do the units really mean?

Hi Folks

I am trying to make a basic car game, using Panda’s built in physics system. I have been following this guide, successfully implementing LinearVectorForce objects ,and have come to the last step, which is to apply a torque to the centre of gravity of the vehicle, causing it to rotate.

The torque is a result of the difference between lateral forces on the front and back wheels.

My problem is, I don’t understand what the units of AngularVectorForce(X,Y,Z) are. First, since LinearVectorForce is measured in Newtons, I assumed they were Newtons, and tried (250,0,0) as a test. This makes my 1000kg vehicle spin like a top, it is clearly far too much force!

Is there a sensible formula to convert a linear force at a given distance from the centre of gravity into whatever units the AngularVectorForce works with?

Thanks for the help!

angular forces are messured in newton*m. calculation is as easy as calculating the force * the distance to the point around you rotate. (in case your forces are orthogonal)

that’s only one part of the problem. the other is the thing you rotate with that torque. mass distribution is critical there. rotation a mass of 1000kg which is all concentrated in a single point takes no torque at all. if you have a huge ring with the same mass, you need a LOT to accelerate it.

so if your car spins like crazy, also check what ode-mass you used (using a box with the size of your car + your mass will work, make sure the box has the correct size, it’s critical for angular acceleration)

Thanks Thomas for your reply

I understand that the torque forces are measured in Nm, but I think you hit the nail on the head with the point mass issue, that is what I was missing.

As I said, I’m not actually using ODE, I am using the built in Panda physics. As I understand it though, the built in physics treats everything as a point mass… so how is the AngularVectorForce supposed to work? Is there some way to distribute the mass?

I have been reading more about torque in the API and generally. It seems that the AngularVectorForce is an “angular momentum”.

According to Wikipedia,

If I call getInertialTensor() on my PhysicsObject, it returns a 4x4 matrix that looks like this

1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1

Looking at this list of inertial tensors on Wikipedia though, it seems they are always 3x3 matrices

It seems, if I can figure out the relation of that 4x4 matrix to the 3x3 one, I will have all the pieces of the puzzle and be able to calculate the value to give to AngularVectorForce.

Can anyone help me fill in the blanks?

Did my matrices scare everyone away? 'cos they scare me too :open_mouth:

If anyone can shed any light it would be greatly appreciated, my game is going to be terribly boring if the cars can only go forwards and backwards :wink:

For the record, that is the identity matrix, which stands for no transformation. The identity matrix is defined as a square zero-filled matrix with 1’s at the diagonal. So the 3x3 matrix equivalent would be:
1 0 0
0 1 0
0 0 1

Just clearing that up. Won’t help you much, though, sorry.

Had that problem too but didnt find an answer yet.
Maybe if you take a dive into the panda-sources… (that didnt help me but i dont know c++ beyond “hello world”)

Glad to know I am not alone at least :slight_smile: My knowledge of c++ is rudimentary at best, but perhaps I will brave the source. There certainly doesn’t seem to be any other information on these elusive AngularVectorForces. I have scoured the forums and APIs and the web in general to no avail.

Ok, so, I have had a bit of a look at the source (hopefully I am looking in the right places). I came across this in “physicsObject.cxx”

////////////////////////////////////////////////////////////////////
//     Function : get_inertial_tensor
//       Access : Public
//  Description : returns a transform matrix that represents the
//                object's willingness to be forced.
////////////////////////////////////////////////////////////////////
LMatrix4f PhysicsObject::
get_inertial_tensor() const {
  return LMatrix4f::ident_mat();
}

Unless I am being stupid, this means that get_inertial_tensor() will always return the 4x4 identity matrix, so it is a bit meaningless.

The “add_impact” function doesn’t appear to be complete either. It just adds a “spin” equivalent to the magnitude of the force vector, without any accounting for mass or rotational inertia.

////////////////////////////////////////////////////////////////////
//    Function : add_impact
//      Access : Public
// Description : Adds an impulse and/or torque (i.e. an instantanious
//               change in velocity) based on how well the offset and
//               impulse align with the center of mass (aka position).
//               If you wanted to immitate this function you could
//               work out the impulse and torque and call add_impulse
//               and add_torque respectively.
//               offset and force are in global (or parent) coordinates.
////////////////////////////////////////////////////////////////////
void PhysicsObject::
add_impact(const LPoint3f &offset,
    const LVector3f &force) {
  nassertv(!offset.is_nan());
  nassertv(!force.is_nan());
  LVector3f a = offset;
  LVector3f b = force;
  a.normalize();
  b.normalize();
  a = a.cross(b);
  float angle = a.length();
  if (angle) {
    LRotationf torque;
    float spin = force.length()*0.1f; // todo: this should account for
                                      // impact distance and mass.
    a.normalize();
    assert(IS_THRESHOLD_EQUAL(a.length(), 1.0f, 0.001f));
    torque.set_from_axis_angle(spin, a);
    add_torque(torque);
  }
  LVector3f impulse = (1.0f - angle) * force;
  add_impulse(impulse);
}

For completeness, here is the “add_torque” function from “physicsObject.I”. You can see that it doesn’t take mass into account at all.

	////////////////////////////////////////////////////////////////////
 	// Function : add_torque
 	// Access : Public
 	// Description : Adds an torque force (i.e. an instantanious change
 	// in velocity). This is a quicker way to get the
 	// angular velocity, add a vector to it and set that
 	// value to be the new angular velocity.
 	////////////////////////////////////////////////////////////////////
INLINE void PhysicsObject::
add_torque(const LRotationf &torque) {
  nassertv(!torque.is_nan());
  _rotation+=torque;
} 

I may be mistake, since I am not very fluent in C++ and this is the first time I have tried delving into a source code repository, but it seems like AngularForces are not fully implemented yet. I would love to be proved wrong though…

The get_inertial_tensor, add_impact and add_local_impact methods are virtual and can be overridden by classes that derive from PhysicsObject.

Aha, that clears things up a bit, thanks.

Am I correct in thinking that I will have to make my own class that inherits from PhysicsObject but overrides those virtual functions if I want to use the AngularVector forces (and have them take mass into account)?

So, did you figure this out? I ask because I’m interested in using the default panda physics (pretty basic needs). From reading this it seems it doesn’t have a complete implementation of torque; if so I’ll just use ODE.

As to the 4x4 matrices above, doesn’t Panda use quaternions for its calculations? Those would be 4x4. That said, I haven’t used them enough to know what forms rigid body physics will take with them.

EDIT: Just saw your other post, so I’m guessing you didn’t figure it out. On to ODE!

Unfortunately I never did figure it out. I came to the conclusion that torque was not fully implemented (but I may be wrong).

ODE is great though. I had been avoiding it because I was just wanting to do a simple arcade car game and I thought it would be overkill, but it is actually (relatively) easy to use once you get into it. Documentation is a bit sparse though.