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
and add
Also in the same file down the bottom find this
and add
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
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
If you want to have a little fun pushing things around then add this to your player onCollision:
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 ;-)
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 ;-)
#162
09/25/2006 (2:13 pm)
Where you looking at, should be under shapes. If not there email me your boulder.cs and will take look at it.
#163
09/26/2006 (9:43 am)
i just copied the datablock from the resource... that's all.
#164
09/26/2006 (10:01 am)
You have rigidShape.cs and boulder.cs in server/scripts and exec in games.cs. Did you delete the game.cs.dso. The path to the boulder is Shapes/RigidShape. The path the dts is it correct in boulder.cs.
#165
09/27/2006 (5:05 am)
the rigidShape.cs and boulder.cs is in the server/scripts-folder, is executed in game.cs, i have deleted game.cs.dso, added the boulder to a folder in data/shapes named "boulder", and the only place where boulder.dts shows up in the world editor is in the static shapes... what am i doing wroong? *rips some hair off the head*
#166
Works like a charm now =)
09/27/2006 (6:15 am)
Nevermind me, i am retarded. I forgot to copy the Torque Demo OSX from the Default folder..Works like a charm now =)
#167
Keep in mind that I'm new to torque, so I guess these might be done better (and probably must: I guess objects can get double impulse at wakeups depending on the order of solving)
@rigid.cc:
@rigidShape.cc:
Hope these help.
10/25/2006 (8:33 am)
I fiddled around a bit with HEAD and managed a workaround for some of the issues with the RigidShape class (mainly, speed).Keep in mind that I'm new to torque, so I guess these might be done better (and probably must: I guess objects can get double impulse at wakeups depending on the order of solving)
@rigid.cc:
in bool Rigid::resolveCollision(const Point3F& p, Point3F normal, Rigid* rigid) - applyImpulse(r2,impulse); + // Fix: Impulse applied to wrong object + rigid->applyImpulse(r2,impulse);
@rigidShape.cc:
in namespace:
- static int sRestCount = 10; // Consecutive ticks before comming to rest
+ static int sRestCount = 5; // Consecutive ticks before coming to rest
void RigidShape::updatePos(F32 dt):
- if (k < sRestTol * Kg && ++restCount > sRestCount)
- mRigid.setAtRest();
+ if (k < sRestTol * Kg) {
+ if (++restCount > sRestCount)
+ mRigid.setAtRest();
+ } else
+ // FIX: restCount wasn't reset
+ restCount = 0;
+ }
in void RigidShape::updateForces(F32 /*dt*/):
- mRigid.atRest = false;
+ // Fix: Gravity doesn't wake up objects (eg: lying on the floor)
+ // mRigid.atRest = false;
in bool RigidShape::resolveCollision(Rigid& ns,CollisionList& cList):
- ns.resolveCollision(cList.collision[i].point,
- cList.collision[i].normal);
+ // Hack: wake up sleeping RigidShapes
+ // TODO: Interface to mRigid for all physically usable objects
+RigidShape *col = dynamic_cast<RigidShape*>(c.object);
+if (col != NULL && col->mRigid.atRest) {
+ ns.resolveCollision(cList.collision[i].point,
+ cList.collision[i].normal,
+ &col->mRigid);
+}else {
+ ns.resolveCollision(cList.collision[i].point,
+ cList.collision[i].normal);
+}Hope these help.
#168
/pathtomyscript/rigidshape.cs (95): Register object failed for object (null) of class RigidShape"
rigidshape.cs is where I put the datablock and RigidShapeData::create function. I tried echoing the %data variable the create function was receiving, but then I get an error that the RigidShapeData::create doesn't exist, so I'm also baffled at the moment as to how to debug this. Any help would be appreciated.
Edit: I'm using Brian Richardson's port to TSE
11/08/2006 (12:13 am)
I'm getting a weird thing that is baffling me--but then again I am a novice scripter. I added the nice demo boulder and it rolls around just fine. Then I added a second datablock to my "rigidshape.cs" for a tennis ball model, copy/pasted from the boulder one except a different datablock name in the parentheses and different dts model referenced, but when I try to add it I get: "Object 'tennisball' is not a member of the 'GameBaseData' data block class/pathtomyscript/rigidshape.cs (95): Register object failed for object (null) of class RigidShape"
rigidshape.cs is where I put the datablock and RigidShapeData::create function. I tried echoing the %data variable the create function was receiving, but then I get an error that the RigidShapeData::create doesn't exist, so I'm also baffled at the moment as to how to debug this. Any help would be appreciated.
Edit: I'm using Brian Richardson's port to TSE
#169
11/08/2006 (6:49 am)
Hey guys, it should work for a soccer ball?
#170
11/08/2006 (6:51 am)
I would not use it as a replacement for a proper physics modelled soccer ball - but try!
#171
11/08/2006 (11:26 am)
What engine are you using? I just test TGE 1.4, Tlk 1.4 and TGE 1.5, they all work fine. May be we can see your code. If I am understanding you instead copy the whole datablock just do this. You can add things you want to be different. You will only need the one function that is aready there.datablock RigidShapeData( BouncingBox : BouncingBoulder )
{
category = "RigidShape";
shapeFile = "~/data/shapes/RigidObjects/box/box.dts";
emap = true;
// Rigid Body
mass = 10;
};
#172
11/08/2006 (12:21 pm)
Doh! I really should have mentioned I'm using Brian Richardson's TSE port. Up til now, I'd found the script stuff so identical between the engines I'd kinda forgotten the relevance. So I went to try to duplicate the problem in TGE 1.4, and it worked just fine. Must say I'm still baffeld why it doesn't work under TSE, though. All I did was copy/paste the example boulder datablock and changed two lines:datablock RigidShapeData( tennisball )and the path to the tennisball dts. I must say I'm a little confused by the syntax you have with "BouncingBox : BouncingBoulder)..?
#173
11/08/2006 (12:54 pm)
The syntax you mention is how you inherrit datablocks. BouncingBox : BouncingBoulder means that BouncingBox is derived from BouncingBoulder and will have all it's elements.
#174
11/08/2006 (4:53 pm)
You're right Duncan, you can change whatever you want in the datablock. It is amazing how you can inherrit the data but they act completely different, the boulder rolls and the box bounces.
#175
Still...anybody else have this problem (or not) with TSE?
11/09/2006 (1:12 pm)
Ahhhh, that is cool--thanks.Still...anybody else have this problem (or not) with TSE?
#176
BUT...I did chase down another very freaking significant problem. With certain of my models brought in as RigidShapes they would bring TGE to it's knees, sub 1 fps! After only 7 or 8 hours of hacking, I finally discovered that it was because I was scaling these objects up in the Mission Editor. This is a very, very, bad idea! Use the Mission Editor to find the scale your DTS's need to be, but then go back and do the scaling in your modelling app and bring them into the Mission Editor at 1 1 1. *edit: a little scaling doesn't appear to be a big problem. The problem shapes were 10x and 50x.
After doing this on the problem models, I went from 1-14 fps back up to 50. It matters! :-)
(but now I'm delighted)
btw anyone know what causes RigidShapes to sometimes jerk around in mid-air?
11/12/2006 (3:49 am)
By the way, I've seen the "Register object failed" intermittently with TGE 1.5. I haven't been able to pin in down yet, but by and large it works great with 1.5 (the version that's built in).BUT...I did chase down another very freaking significant problem. With certain of my models brought in as RigidShapes they would bring TGE to it's knees, sub 1 fps! After only 7 or 8 hours of hacking, I finally discovered that it was because I was scaling these objects up in the Mission Editor. This is a very, very, bad idea! Use the Mission Editor to find the scale your DTS's need to be, but then go back and do the scaling in your modelling app and bring them into the Mission Editor at 1 1 1. *edit: a little scaling doesn't appear to be a big problem. The problem shapes were 10x and 50x.
After doing this on the problem models, I went from 1-14 fps back up to 50. It matters! :-)
(but now I'm delighted)
btw anyone know what causes RigidShapes to sometimes jerk around in mid-air?
#177
But I have a problem: When the player collides with the bounder nothing happened. This is my bounder-datablock:
11/22/2006 (10:52 am)
Cool Code!But I have a problem: When the player collides with the bounder nothing happened. This is my bounder-datablock:
datablock RigidShapeData( BouncingBoulder )
{
category = "RigidShape";
shapeFile = "~/data/shapes/boulder/boulder.dts";
emap = true;
// Rigid Body
mass = 100;
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;
};and this is my Player-Collision: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 can't fix the problem. I'm using Torque 1.4.2
#178
11/22/2006 (11:14 am)
The default mass for the boulder prevents this. Try lowering it to .1.
#179
Ever when I shot at a rigidShape, Torque freezed.
11/25/2006 (10:47 am)
Now I've got a new problem:Ever when I shot at a rigidShape, Torque freezed.
#180
12/09/2006 (8:29 pm)
ITS LOOKS LIKE THIS COME WITH TGE 1.4.2 IS IT THE SAME THING? 
Torque Owner Alex Palmquist
made all the changes in shapebase.h.
recompiled.
downloaded the boulder in an earlier post.
created rigidShape.cs, used the code Stefan mentioned in one early post.
created boulder.cs and added the datablock in the resource.
executed them both in game.cs... but no boulder showing up in the editor...