Game Development Community

dev|Pro Game Development Curriculum

Rigid Shape Class

by Thomas \"Man of Ice\" Lund · 04/07/2004 (9:57 am) · 256 comments

Download Code File

History
2005-09-08 Updated with performance fix from XoCluTch

What is this?
For my game I needed a boulder that rolls down a hill, and that one needs to evade. Initial attempts to use the existing classes (items, shapes and especially projectiles) fail because of too simple physics and/or lack of collision box support. I was faced with either implementing collision boxes in the projectile class, look into ODE or try to code my own rigid body class.

Thanks to Ben Garney I didnt have to do any of these (thanks ;-) ), as there already exists rigid physics in the engine. The rigid.cc/h files have everything needed, but they are only available as con/net objects using the vehicle classes.

So I simply took the base vehicle class and the hover vehicle class, merged them together and removed most of the unneeded code. The result is actually fantastic, and I cant believe this isnt standard part of Torque.

As the code basically is a hover vehicle there might be parts of the code that should be removed further. If you spot any of those, then post here and I'll update the codebase.

What does it look like?
No resource without a movie :-)
Here is the final result from a tech demo level in my upcomming action adventure game.

www.codejar.com/rigidshape4.wmv

I also did a few early tests and I've included the movies here. The lack of realism is totally due to way too much impulse applied with a large vertical factor + low mass for the chests.

www.codejar.com/rigidshape.wmv
www.codejar.com/rigidshape2.wmv
www.codejar.com/rigidshape3.wmv

All movies are approx 3 MB

How to add
First thing is to add the 2 attached files in the zip to your engine\game dir and to your project. Then open the shapebase.h and find this

class ShapeBaseConvex : public Convex
{
   typedef Convex Parent;
   friend class ShapeBase;
   friend class Vehicle;

and add

friend class RigidShape;

Also in the same file down the bottom find this

#define StaticShape_GenericShadowLevel 2.0f
#define StaticShape_NoShadowLevel 2.0f

and add

#define RigidShape_GenericShadowLevel 0.7f
#define RigidShape_NoShadowLevel 0.2f

Recompile your engine and thats it.

If you want to do this "for real", then one also needs to define a new objectType. I have reused the ShapeBaseObjectType - change that if you want or go through tons of code and add a RigidShapeObjectType.

How to use
From script you now got access to a RigidShapeData datablock and a RigidShape object type. Your DTS object is required to have a mass node, but nothing else. The code still includes dusttrail and splash emitters from the vehicle code, as well as impact + water sound. This example does not use any of those.

An example datablock for a rigid shape is included below

datablock RigidShapeData( BouncingBoulder )
{	

   category = "RigidShape";
	
   shapeFile = "~/data/shapes/boulder/boulder.dts";
   emap = true;

   // Rigid Body
   mass = 500;
   massCenter = "0 0 0";    // Center of mass for rigid body
   massBox = "0 0 0";         // Size of box used for moment of inertia,
                              // if zero it defaults to object bounding box
   drag = 0.2;                // Drag coefficient
   bodyFriction = 0.2;
   bodyRestitution = 0.1;
   minImpactSpeed = 5;        // Impacts over this invoke the script callback
   softImpactSpeed = 5;       // Play SoftImpact Sound
   hardImpactSpeed = 15;      // Play HardImpact Sound
   integration = 4;           // Physics integration: TickSec/Rate
   collisionTol = 0.1;        // Collision distance tolerance
   contactTol = 0.1;          // Contact velocity tolerance
   
   minRollSpeed = 10;
   
   maxDrag = 0.5;
   minDrag = 0.01;

   triggerDustHeight = 1;
   dustHeight = 10;

   dragForce = 0.05;
   vertFactor = 0.05;

   normalForce = 0.05;
   restorativeForce = 0.05;
   rollForce = 0.05;
   pitchForce = 0.05;
};

By including the category="" it now shows up in the world editor under the Shapes, and its fully working. Spawn the object on a hilltop and see it roll down :-)

For the mission editor to work you will need to add a create() function that hooks into the mission editor. You can either put this into a rigidShape.cs file (dont forget to load it from game.cs) or put it into any .cs file in the server\script

// Hook into the mission editor.

function RigidShapeData::create(%data)
{
   // The mission editor invokes this method when it wants to create
   // an object of the given datablock type.
   %obj = new RigidShape() {
      dataBlock = %data;
   };
   return %obj;
}

If you want to have a little fun pushing things around then add this to your player onCollision:

function Armor::onCollision(%this,%obj,%col)
{

...

if (%col.getDataBlock().getName() $= "BouncingBoulder") {
	 // Apply an impulse to the object we collided with
	 %eye = %obj.getEyeVector();
         %vec = vectorScale(%eye, 10);
	 
        // Add a vertical component to give the item a better arc
	%dot = vectorDot("0 0 1",%eye);
	if (%dot < 0)
		%dot = -%dot;
	%vec = vectorAdd(%vec,vectorScale("0 0 2",1 - %dot));

	// Set the object's position and initial velocity
	%trans = %col.getTransform();
   
   // Heres the position and rotation.
   %pos = getWords(%trans, 0, 2);
	%col.applyImpulse(%pos,%vec);	 
}

...

}

I've done a few tests with forces, masses and such - and as you saw from my movies with varying results.

The objects are fully network aware, and I bet this code can replace ODE for most purposes if you dont need total realism.

As I wrote earlier, the code can be stripped down further. There are various pieces of the physics that I do not understand fully and left in. I would be very happy if someone could run through those parts and see if any of it can be taken out.

Regarding performance, I've tried to add approx 20 shapes to a scene and then letting all collide with each other (its in one of the movies actually). I noticed no performance degradation at all with those simple shapes (they had a 6 sided box as collision mesh.

The boulders in the last movie have an approx 25 faced hedra inside it as a collision mesh. I think I had 15 of those in an scene without performance degradation.

These shapes do have 1 problem though, and that is the collision detection that sometimes fails - exactly as vehicles. If they gain too much speed they will dip into the terrain or go through it. I think a lot of people are looking into that problem at the moment here www.garagegames.com/mg/forums/result.thread.php?qt=17384

Enjoy ;-)
#141
04/30/2006 (9:39 am)
Can this rigid shape class handle multiple collision meshes?
#142
05/04/2006 (1:25 am)
@Thomas - Is there something special i need to do to be able to mount a RigidShape object to my player? Of course when it's mounted it should have it's physics disabled and everything. Am i right in thinking i need to modify the rigid code to make that work?
#143
05/04/2006 (2:38 am)
@Thomas - Ok... updating my own post here. To mount a RigidShape on to my player i had to change the setPosition and setRenderPosition functions:

void RigidShape::setPosition(const Point3F& pos,const QuatF& rot)
{
   MatrixF mat;
   if (isMounted()) 
   {
      mMount.object->getMountTransform(mMount.node,&mat);
   }
   else
   {
      rot.setMatrix(&mat);
      mat.setColumn(3,pos);
   }

   Parent::setTransform(mat);
}

void RigidShape::setRenderPosition(const Point3F& pos, const QuatF& rot)
{
   MatrixF mat;
   if (isMounted()) 
   {
      mMount.object->getRenderMountTransform(mMount.node,&mat);
   }
   else
   {
      rot.setMatrix(&mat);
      mat.setColumn(3,pos);
   }

   Parent::setRenderTransform(mat);
}

And then at the top of processTick i did:

void RigidShape::processTick(const Move* move)
{
   Parent::processTick(move);

   // When mounted to another object we take it's
   // transforms and do no physics, collision, or
   // nothing!
   if (isMounted()) 
   {
      mRigid.linVelocity = mMount.object->getVelocity();
      setPosition(Point3F(), QuatF());
      setMaskBits(PositionMask);
      return;
   }

   // Warp to catch up to server
   if (mDelta.warpCount < mDelta.warpTicks) {
      mDelta.warpCount++;

So mounting works. My issue now is unmounting. It leaves the state of mDelta and mRigid all screwey and your shape will jerk around like made once unmounted. Anyone know the right way to get this thing into the right state once it's unmounted?
#144
05/06/2006 (9:05 am)
#145
05/10/2006 (11:29 am)
BUG?
MASS NODE position/location will NOT effecting the Mass Center, same for the datablock variable 'massCenter'. (try any numbers you want, will not change the mass center)

Work Around?
I have found the only way to place 'MassCenter' is to locate the 'Bounds' box at the location I wish the MASS Node to be. Less the fact, without the Bounds encompassing the full mesh the shadows created from the mesh will be clipped.

Perhaps i do not know how to use the 'Mass Node' or the massCenter variable correctly?
#146
06/21/2006 (4:46 pm)
Torque crashes when i add an RigidShape Object.
Anyone with the same problem?

Edit: it works using the boulder.dts, but not works with my own model. I've added a mass joint but it still crashing.
#147
06/21/2006 (5:50 pm)
How detail is your collision box? You need a very simple convex collision box.
#148
07/08/2006 (4:11 pm)
I'm having a heck of a time figuring this out....when I call setHidden(true); on a RigidShape, Torque crashes. I cannot figure out why this is happening...anyone?
#149
07/13/2006 (1:40 am)
I'm having the sliding-not-rolling problem, and no amount of tweaking to bodyFriction seems to help. Any ideas what I'm doing wrong?

The spherical object I'm using seems to react as if it were struck near the ground, like imparting backspin to a pool ball. It even rolls backwards like a backspun ball would. I've tried tweaking massCenter, drag and bodyFriction, with no luck. The effect worsens when I've got a high rebound on it through bodyRestitution.

I've tried moving the mass node off-center in the DTS... no luck there either.

These settings have provided the best results so far, but they're still far from ideal.
mass = "5";
	massCenter = "0 0 0";    
	massBox = "0 0 0";
	drag = ".5";
	bodyFriction = "2";
	bodyRestitution = ".1";

Any clues you can offer would be greatly appreciated! I'm stumped.

@Rubes: When I try applying setHidden, I get a "Must be in a container!" error... is that what you're getting?
#150
07/13/2006 (7:08 am)
I dont think the mass node matters in the code. It uses the pivot point as center.

For sliding its usually a matter of your collision shape not having enough faces, so it slides on one of those without enough rotation to flip to the next face!

Never tried to apply the setHidden()!
#151
07/13/2006 (7:34 am)
I started a thread on the setHidden() problem here, and that seems to have resolved the problem. Had to do with collision checking, which was continuing after the object was removed from the scene with setHidden(), and this caused the crash.
#152
07/15/2006 (6:15 am)
@Thomas: I don't think it's a collision mesh issue. The problem occurs whether I'm dealing with a cube or a 20-sided geosphere (with matching collision meshes). As soon as I apply enough force to tumble the object, it starts behaving erratically. Additionally, some of the changes in direction occur in midair, with no collision!

I'm wondering if it's an axis problem... the reaction of my test objects is almost like a destabilized rocket, spinning out of control as the thrust points in whatever direction it happens to have tilted to. Or letting go of an inflated balloon: the way it flies erratically around the room as it deflates is very similar to the behavior of my cubes and spheres -- pblblblblblblblpt, plop.

I notice that (a) the sun is coming up and (b) I've resorted to sound effects to describe physics. It must be well past my bedtime. While I crawl off to bed, maybe one of you diurnal folk will have a thought on how to troubleshoot this...

G'night! =)

-- JohnDopp
#153
07/19/2006 (9:09 am)
this thing is awesome!!

I sort of know nothing about modelling (programmer here)... i was wondering how do i add a mass node to a dts object? here we only have maya 7.0 with the dts utility v.1.0.6

i have a regular dts and it falls right through the level.
i double checked by adding the boulder and it works perfectly but i want to know how to add these mass nodes to othe objects.
#154
07/24/2006 (4:02 am)
This is a great resource. If you are having problems moving the Rock, Box, what ever you have as a Rigid Shape, you may want to place a friendly echo("call something here"); inside your on player Armor::onCollision(). I spent the better part of a day trying to get my guy to push the Boulder....after spending all my time with Visual Studio, Torsion, variables, playing with Forces....I asked a simple question. "Is the Guy even touching the darn boulder?" and the answer was no. I rolled back to an earlier point and BAM!!! The Rock was flying all over the place, I was even able to shoot it, something I didn't even expect to get right out the box.

So, if you are about to kick something because you think it isn't working -- you can still kick something...I am not going to take the fun out of that :), but when you are finished kicking stuff, make sure you don't have any other resources bumping heads with your collision. I still don't know why collision is not being detected...but at least I have my problem...and thought I share with you guys.

-NTX
#155
07/26/2006 (5:27 pm)
Hey guys, I figures something else out that I haven't seen mentioned here. I wasn't able to get the boulder to move when I shoot it... I have Chris Calef's Ragdoll pack installed. if you follow his directions he has you removing a line in your radiusDamage function which may prevent your weapon from moving an object when shot. So do not remove this line when told:

location: radiusDamage.cs
%targetObject.applyImpulse(%position, %impulseVec);

So far I have the function he provides and this line working together.

I am also using the unedited line inside of all my weapon scripts oncollision function.
radiusDamage(%obj, %pos, %this.damageRadius, %this.radiusDamage, "Radius", %this.areaImpulse);

I hope this helps anyone having any issues.

edit:
you may also need to add back areaImpulse = 200; inside your ProjectileData Datablock if you had removed it.
#156
09/16/2006 (4:14 pm)
hey guys, i have been playing with the rigid shapes for a while with a column but whenever i drop it it always comes back up like a weeble. Is there a way to stop this from happening. i have been playing with bodyRestitution but i guess this is not the variable that will do that. any ideas?
#157
09/16/2006 (4:18 pm)
@Univ. of Central Florida (#0029) - My guess is your origin of your column is on the bottom. Since the center of mass defaults to the origin it would do as you describe. Either export the model with the origin at the geometric center of the column or offset the center of mass.
#158
09/17/2006 (4:54 pm)
I put a bunch of these shapes into the system and it really bogged down. I think I had like 6 or 7 objects and it got really slow. I don't think it is something that probably be fixed other than checking for the object being at rest. I did have fun and made myself spawn as a ball that rolled around. I just told myself, "Be the ball.".

Very cool resource. This is a good starting point for me to understand collisions and such.

Thanks,
Frank
#159
09/18/2006 (10:34 am)
Thank you for you help,

i played with the rigid shape all week but the column is still standing up. i played with the massCenter like you suggested but the column is still standing up.

is there anyway i can post the model or does anyone have any other suggestions in order for the column to stay down.
#160
09/18/2006 (1:11 pm)
From the new features of TGE 1.5...

Quote:Added an enhanced version of RigidShape for doing simple rigid body physics in a generic way

So I guess this is being added in.