OgreNewt hovercraft

batonrye

25-03-2006 23:32:02

For my current project, I'm implementing a hovercraft with OgreNewt, but I have a few questions... :mrgreen:

I understand the physics pretty well, but as far as implementing things correctly with OgreNewt (callbacks, fastdelegate), I'm a bit lost (even after much reading and researching documentation)

Here as how I plan on setting things up (without knowing any better)

:arrow: A Hovercraft class (pretty much laid out now) which contains the Newton body object for the chassis, any (purely cosmetic) detachable objects like fenders, wings, etc, all the ogre models and materials used, various performance variables (speed, hover height, turn...) and an array of 6-9 position vectors representing "jets" that provide the hover force.

There is an Init method for the craft that does some calculations and arranges the jets.

Now here is where I get fuzzy: I also have a hoverCallback method inside of the Hovercraft class (this goes though the jets, calculates rays, and gives the correct "hover" force on the body)

void Hovercraft::hoverCallback( OgreNewt::Body* chassis)
{
//calculations....
}


Now back up in the Init() function, i have it set the callback:

chassis->setCustomForceAndTorqueCallback( fastdelegate::MakeDelegate( this, &Hovercraft::hoverCallback) );

If the hovercraft "dies" i set the chassis to a normal gravitational force callback.



Here is the whole thing in pseudo code:

class Hovercraft
{
//Ogre geometry

OgreNewt::Body* chassis

Ogre::Vector3 nozzles[6];
Ogre::Real hoverHigh;
Ogre::Real maxSpeed;

// other data members
// ....
// ....

void HovercraftInit(size, mass, height, etc...)
{
//Calc jet thrust, jet locations

//Set Newton collision geom, attach Ogre scene node, etc.
chassis->setCustomForceAndTorqueCallback( fastdelegate::MakeDelegate( this, &Hovercraft::hoverCallback) );

}

void Hovercraft::hoverCallback( OgreNewt::Body* chassis)
{
// accumulate force and torque for each jet
//Apply net force and torque to the chassis
}

}


I guess that I'd just like to know if I'm on the right track, and maybe some pointers... thanks in advance for any help

walaber

28-03-2006 16:22:06

you are exactly on-track. in the callback you should use raycasts to determine the distance between the various jets and the ground (or other objects) and apply a force based on that distance both to the chassis, and the ground object (if it is a dynamic object).

on a general level, your structure looks perfect to implement what you want to do. :)

batonrye

28-03-2006 23:49:52

Great, thanks!

OvermindDL1

29-03-2006 06:33:07

I have a hovercraft that emulates one from another game. I just use the boyancy callback and set the plane to always face up and be however high the thing hovers from the ground above that. Works quite well.

batonrye

29-03-2006 07:37:17

hmmm... i like that idea.

When you refer to "up" do you mean up vs the normal of the ground below, or a world space up vector? Having it strait up it seams would cause problems going over rough terrain. I'll have to set it up and try it out.

OvermindDL1

29-03-2006 14:01:04

I have it world-space up, reason being that if you are on an incline, it starts to slide down if it is the terrain normal, if it is world up then it will not slide down. Have not noticed any problems with this method thus far.

batonrye

13-04-2006 05:37:39

OK -

I have made much progress with my hovercraft, but I seem to have a problem factoring in torque. Basically, with my netTorque addition commented out, the craft works just as expected - it drops to the ground and comes to a gentle hover after just a bit of oscillatory motion) However, with the torque enabled it spins wildly like a top! If I disrupt it with a projectile, the thing goes crazy. Fun to watch, but not the result I am after!

BTW it’s the Y axis it is spinning on (so its stays upright, just turning around)

Here's my callback. I should have paid more attention in physics. :?


void Hovercraft::hoverCallback( OgreNewt::Body* craft)
{
// Accumulate force and torque for each jet
// Apply net force and torque to the craft

Ogre::Vector3 inertia;
Ogre::Vector3 veloc;
Ogre::Vector3 omega;
Ogre::Vector3 position;
Ogre::Quaternion orient;
Ogre::Vector3 nozzleDir;

craft->getMassMatrix(mass, inertia);

Ogre::Vector3 netTorque(0.0f, 0.0f, 0.0f);
Ogre::Vector3 netForce( 0.0f, - mass * 9.8f, 0.0f);

craft->getPositionOrientation(position, orient);

//direction of nozzel to apply force
nozzleDir = orient * Vector3::NEGATIVE_UNIT_Y;

// get the velocity of the craft
veloc = craft->getVelocity();
omega = craft->getOmega();

// calculate the force and torque for each nozzle
for (int i = 0; i < 6; i ++) {
float distance;
float nozzleForce;
float nozzleDampForce;

// get the nozzle position in global space
Ogre::Vector3 nozzlePosit = position + (orient * nozzles[i]);

// get the point at wicth the nozzel becomes inefective
Ogre::Vector3 nozzlePositEnd = nozzlePosit + (nozzleDir * maxHover);

// the the effective nozzle distance
distance = maxHover * (1.0 - RayCast(mWorld, nozzlePosit, nozzlePositEnd));

nozzleForce = nozzleThrust * distance;

// dampen the nozzel force
Ogre::Real nozzleDampCoef = 0.2;
Ogre::Vector3 nozzleVeloc = veloc + omega * nozzlePosit;
nozzleDampForce = - nozzleVeloc.dotProduct(nozzleDir) * mass * nozzleDampCoef;

// calculate the total nozzle force
Ogre::Vector3 force = nozzleDir * (nozzleForce + nozzleDampForce);

// calculate nozzle torque
Ogre::Vector3 torque = (nozzlePosit * force);

// add up force and torque
netForce += force;
netTorque += torque;
}

craft->setForce(netForce);
craft->setTorque(netTorque);
}

OvermindDL1

13-04-2006 22:53:10

As I recall, you should never touch torque. I'll post up my callback when I get home in 7 hours or so (or I get a free enough break at work), but I use the bouyency callback instead of applying my own forces. Took a great deal of time to get the numbers balanced well so the thing is actually handlable. I have the updated binary available from a certain module on my svn server on my local computer, but I don't recall if I had anon access enabled, don't think so. If it is then you can try to get my current version from svn://overminddl1.no-ip.info/Physics_PlayGround/Release/ and give it a try. Left click spawns a unit in front of you (you start 200 meters in the air so it will take a little time for it to fall, might want to move down first, wasdfc for movement), right click removes a unit from in front of you, middle click and 'e' both cause you to 'possess' (take control of) the unit that is in the center of your screen, and mouse4 (back) will change you view to the unit in the center of your screen (but not control it, good to set to a unit after you possess another so you can drive around and see how fast you go from another perspective). Shift multiplies all translations by 10, space multiplies all by 15 as I recall. All movement and physics settings for that craft is in the .odf file in the root directory (not the odf directory, that is my new system that the old vehicle is not using, it is in the process of being replaced), so you can change things if you want to see how it reacts. The current settings are nicely controllable as I recall. If anon is not enabled then I can enable it when I get TS or local access to my machine again if you wish (assuming I remembered to turn the server on). And of course, I can post my callback code if you want it. The only issue right now is that if one hovercraft bumps into another they tend to rotate wildly for a second, and if you go too high above the hover plane, then dive straight for the ground, you end up going through the ground, then hovering back up to bump into the bottom of the ground without going all the way back up, stuck there basically.

EDIT: Just checked, svn server is up, but anon access in that area is disabled, will enable if you ask when I get a chance to TS or local into it, else I leave it anon off.

pfo

14-04-2006 00:43:23

It looks to me like the problem might be that you are calculating torque using the cross product with a point in global space. You want to cross product your force with the point local to the craft (i.e., local nozzle position). Also, if you're using Julio's posting at the Newton forums as a reference, be aware that his vector * vector operator is a cross product, not a multiplication.

OvermindDL1

14-04-2006 01:51:01

Anon access is enabled for that module only, will disable again next time I turn off the computer.

walaber

14-04-2006 01:54:47

is there any reason you are calculating the force and torque by hand? why not use addLocalForce() or addGlobalForce() for each nozzle?

these functions calculate the force and torque for you for a force applied to a specific point, in a specific direction (in either local or global space)

batonrye

15-04-2006 07:36:01

is there any reason you are calculating the force and torque by hand?

After reading more about the newton API, no, i do not... :roll:


Alright, I finally got the thing working right (mostly), thanks guys.

Just trying to make things more stable, and add some input controls at this point. My debug info is at the bottom of the screen though. All Im doing is using mWindow->setDebugText(mHover->debugInfo); to post a string of debug info from the hover craft.


batonrye

15-04-2006 22:35:13

@Overmind:

I am interested in seeing your callback code, but was not able to connect to your machine via SVN.

If its not too much trouble, can you post here in the forums? - or my email is:

batonrye[AT]gmail.com

Thanks!

OvermindDL1

16-04-2006 01:39:05

Yea, I took svn access off (when my computer shut down actually) some odd 12 hours later. My callback code is simple (and mostly for testing, but it works currently). It is:
void Hoverer::forceCallback( OgreNewt::Body* me )
{
Real mass;
Vector3 inertia;

me->getMassMatrix(mass, inertia);
me->addForce(gravity*mass);
Real moveScaled = moveAmtPerTick;
if(m_MoveFast) moveScaled *= moveFastMultiplier;
if(m_MoveVeryFast) moveScaled *= moveVeryFastMultiplier;
if(m_MoveSlow) moveScaled *= moveSlowMultiplier;

Vector3 moveAmt(0.0f, 0.0f, 0.0f);
if(m_MoveForward) moveAmt[2] += moveScaled;
if(m_MoveBackward) moveAmt[2] -= moveScaled;
if(m_MoveLeft) moveAmt[0] += moveScaled;
if(m_MoveRight) moveAmt[0] -= moveScaled;
if(m_MoveUp) moveAmt[1] += moveScaled;
if(m_MoveDown) moveAmt[1] -= moveScaled;

me->addLocalForce(moveAmt*moveSpeedMultiplier, Vector3(0.0f, 0.0f, 0.0f));

Vector3 turnAmt(0.0f, 0.0f, 0.0f);
bool doTurnForce = false;
if(m_RotateLeftRight)
{
doTurnForce = true;
turnAmt[0] = -(m_RotateLeftRight)*rotateMultiplier;
m_RotateLeftRight = 0.0f;
}
if(m_RotateUpDown)
{
doTurnForce = true;
turnAmt[1] = -(m_RotateUpDown)*rotateMultiplier;
m_RotateUpDown = 0.0f;
}
if(m_RotateClockwiseAndCounter) // TODO: Implement rotation if desired
{
m_RotateClockwiseAndCounter = 0.0f;
}

if(doTurnForce)
{
me->addLocalForce(turnAmt, turnPos);
}

me->addBouyancyForce<Hoverer>(fluidDensity, fluidLinearViscosity, fluidAngularViscosity, gravity*mass, Hoverer::buoyancyCallback, this);
}

bool Hoverer::buoyancyCallback(int colID, OgreNewt::Body* me, const Ogre::Quaternion& orient, const Ogre::Vector3& pos, Ogre::Plane& plane)
{
plane = Plane(Ogre::Vector3(0,1,0), Ogre::Vector3(0,hoverHeight,0));
return true;
}


It is on a flat plane right now, and I'm remaking it to get hoverheight based on point above ground as I finish writing my new class system, but this works. I pull the variables in using a config file, current settings are:
gravity=0 -98 0
fluidDensity=0.5
fluidLinearViscosity=0.0001
fluidAngularViscosity=0.000
angularDamping=10 10 100
linearDamping=5.0
mass=75.0
size=5 3 5
inertia=4.0 4.0 5.0
centerOfMass=0.0 -0.1 0.0
hoverHeight=-190.0
moveAmtPerTick=10000.0
moveFastMultiplier=10.0
moveVeryFastMultiplier=20.0
moveSlowMultiplier=0.25
rotateMultiplier=600.0
turnPos=0.0 0.0 2.0
modelName=fvtank.mesh
moveSpeedMultiplier=0.75 0.1 1.0


My test object is too large, that is why I have such a high gravity to compensate (I have a new version that the new class system's Hoverer class is using). I can post up the current release version if you want, better yet, sec... Okay, svn anon at the above address (for the release binary test) is back on, will keep it up for a few hours (or until windows locks up again, I need to move svn to my bsd box).

praetor

17-04-2006 01:28:23

Torque is just too dangerous to play with manually. Since it isn't a physically "real" entity it just gets screwy. Better to just use straight forces and let the math work the torque out automatically, as torque is nothing more than a mathematical consequence anyway.

batonrye

17-04-2006 07:05:54

@OvermindDL1:

Thanks a bunch - SVN success. You seem to have set it up your code very well.

....unfortunately, with exams right around the corner I can't dive into it quite yet :(

OvermindDL1

17-04-2006 09:26:00

I never actually make games for myself, I am in collage as well and have no time to dedicated to something that expansive. But a couple people are using my engine code to build things. I try to make things as absolutely simple to use in C++, at the expensive of speed on occasions (as long as the code is not part of that 5-10% that is run often). I use Ogre (obviously), OgreNewt (again, obviously), OpenAL++, etc... I intend to use RakNet for networking, and I have networking bindings ready, just have not linked em yet. I may end up just using HawkNL since my class system handles all the replication, serializing, storage, etc... anyway, and since it's license is friendlier. Theoretically, as long as no external libraries outside of what I am using are going to be used, it should be safe to sell (not that they intend to, I just *hate* restricting things, as per note, I hate the gpl, freaking virus, I like the BSD license best). I use *heavy* template and macro programming. Most things will derive from Object. Without you needing to do anything else you will get a "Class" customized for you object type. Class doubles as a factory, memory pool, safe-casting, start of script linking (going to use stackless python, not setup yet in this new system), relationship testing, serialization handling, etc... All that is required to use it is to just add a single macro to your Object derived class. That macro sets up many things, including the templated Class that will be specialized to your Object. You can lazy setup your object into the Class system by calling a single static function on it at any time (good for dll's and all such), or just add a single macro to the .cpp file of the class (or anywhere really, safe to call multiple times) in any global area and the Class will be instantly available to the Class system. You can instantiate any Object by doing a line like (assuming a class called Hoverer):

// If you have the header in the file, just do:
objectPtr newUnit = Hoverer::getClassStatic().Spawn(); // you could add a string with a *unique* name if you don't want one auto generated.

// If you have to go the long way, don't know anything about the class other then what it is called, then just:
objectPtr newUnit = Class::Spawn("Hoverer");
// or the functionally equiv, but more verbose way, in case you don't know if the class even exists or something...
Class *hoverer = Class::findClass("Hoverer");
if(hoverer)
{
objectPtr newUnit = hoverer.Spawn();
}

// The Spawn functions can take a variety of values, a unique name as stated above, location, rotation, etc... Defaults are fine though, they can be positioned once created if you want.
// The objectPtr also has clas specific versions, if you have the class header in, just use, for example, Hoverer::myClassPtr instead


That same Hoverer class would very simply be setup like:

// header file:
class Hoverer : public Object
{
/* ... */

static Real s_HoverHeight;

DEFAULT_CLASS_WITH_FLAGS(Hoverer, Object, CLASS_Abstract)
{
String tempString = cf.getSetting(String("hoverHeight"), String("Hoverer"));
if(!tempString.empty())
s_HoverHeight = StringConverter::parseReal(tempString);
}

/* ... */
}

// implimentation file:
Real Hoverer::s_HoverHeight = 5;

/* ... */


I am currently replacing the static var config setup with another method, but right now that is how it works. You can also just put a semicolon at the end and use another macro to setup the config in the implimentation file. I recently finished my console, supports auto filling list and value displaying. As you type it fills in the auto-completion list with the closest matches first, and the least likely last (usually, but not always related to exact text typing). If you have one selected in the listbox or you type a fully qualified name, it displays the value (or just hit enter then to display it in the box. You can type a value after it to change it. Currently you can link it to booleans, ints, uints, reals, vector3's, and functions (including member functions using boost::bind). You just call one function (even at global scope if the call will always be valid even across levels) to set it up, pass the variable/function to link to, the console name, help text, and flags (help and flags are zero'd out if omitted). If the thing the function returns ever goes is destroyed/goes out of scope, then it is delinked. It is called, for the Hoverer I have on the hoverHeight like:
static ConVar conVar_hoverHeight("Hoverer.hoverHeight", Hoverer::hoverHeight, "This will set the default hover height above ground for the Hoverer object.");
It is at global scope so it is always valid. Here as an example of the current console I have, not a good word to pick as it just happens to match the first characters of the words it thinks are wanted, but meh.


If anyone wants any code just ask, it is no where near complete, and as a whole not usable, but little things (like the console and Class system) are usable.

EDIT: BAH, forgot this forum was phpBB2 (I really don't like it), so a slight issue with the img tag being inside a url, so I seperated them...

EDIT2: Freakin, phpBB2 seems to have a real issue with image tags, that exact line works on my forum, and on all the ones I frequent often. I say again, I really hate phpBB2. If anyone sees why this line does not work, post please? It works fine here, which is the first time I posted.

batonrye

18-04-2006 00:28:05

I run phpbb2 on my forum and have been pretty happy. Phpbb does NOT however allow you to post images without an actual static link (IE an image returned from a php script will not work...)

Not too much of an issue for me, however. Phpbb2 does not support attachments without a mod, and lacks a few of the other features that Simple Machines has. (Like WAP support, which would be kinda neat...)

You can enabe Phpbb2 to allow html tags in the post (it is not enabled here) and i bet your inlined image would show up then.

OvermindDL1

18-04-2006 04:50:57

Phpbb does NOT however allow you to post images without an actual static link (IE an image returned from a php script will not work...)
Yea, don't get why, and its not an image returned, it just dumps the data straight out. Take a look at my signiture, it is generated with every call to it, yet it works fine. As stated, I've never had a good experience with phpBB2, and the admin side is a horror in and of itself.

Phpbb2 does not support attachments without a mod, and lacks a few of the other features that Simple Machines has. (Like WAP support, which would be kinda neat...)
Actually I prefer IPB, but since it went paid only, SMF is next best. I don't understand why phpBB2 doesn't natively support many of these things, every other forum type I've touched supports them out of the box, if you don't need them, a single tick box disables them.

You can enabe Phpbb2 to allow html tags in the post (it is not enabled here) and i bet your inlined image would show up then.
Too much work, not the purpose, the img tag is supposed to display an image, not basterdize it. Besides, allowing pure html posting is a huge security hazard, could get your password pretty easily then if you are running scripts enabled. On my forum, I am the only one with html posting enabled.

Going back to the above, why does my signiture work fine then. I made the script myself, by changing paramaters, you can change the font size, color, wordwrap point, few other things, and it is working fine. phpBB2 just has issues, I leave it at that and contend with the fact it is a piece of junk this off-sites like Ogre use.


And yes, if you are wondering, I have had *extremely* bad experiences with this forum brand. Coding is terrible, the html it generates by default is anything except complient, a terror in and of itself to mod, etc... I see things more from the coding side, and phpBB2 is not what you would consider nice. I used to work for a place doing programming web work in PHP, I already knew php inside and out by that time, but I had to make some slight modifications to phpBB2, you'd have to pay me a good million a month to touch it again. Not really big on PHP overall, but it is convienient, fast, and near supported everywhere. I prefer python for web stuff personally, that is what my site on my home computer runs, cherrypy python websystem on FreeBSD.

EDIT: Testing something:


EDIT 2: Nope...

EDIT 3: Nope again...

EDIT 4: Ah HAH, see, I can get it working and it proves beyond any doubt that phpBB2 is just horribly programmed. Why a programmer would use something programmed as this forum brand is I will never know...

Sorry, my rant for the week. >.>

batonrye

21-04-2006 06:40:18

yes, phpbb is a cold cold bitch to mod :(



..now that i think about it my current install is only "half" working lol

given that the conversion utilities are going to accept my poor mangled "manually edited" database without grief, I have been considering a conversion to another forum engine. Just haden't decieded on one yet. (Or maybe I am just lazy and with very little free time to mess with something that is "working," at least at the moment)

you may have made a SMF fan out of me. :wink: I was familiar with IPB but had never heard of SMF...

OvermindDL1

21-04-2006 10:26:20

SMF is technically the latest version of YaBBse, and installing mods for it is... pretty rediculously easy. :P

Of the free ones, I'd say it is the best.