Setting Terminal Velocities and Rotating Geometry

At DP’s suggestion I am switching over to the new PhysicsSystem that they built. I’ve run into two problems.



THe first involves rotating the ship. My plan was to allow the user to rotate the geometry of the ship. Then whenever a force is applied to move the ship I just multiply the rotation matrix by the forward force to get a force that moves the ship in the correct direction.



THe problem is my ship will only rotate one “tick” before it sets itself back to the original orientation. If you hold down the rotate key the ship will “shake” as it tries to turn but keeps getting set back to the original position. After I make the rotation to the geometry I call shipObj.syncToGraphical(false);. If I don’t make the call to PhysicsWorld.getInstance().update(); everything works fine. Any ideas why this might be happening?



The second problem involves ODE being too realistic. Right now the terminal velocity of my ship is way too high. I want it to have a nice zippy acceleration but I want to cap the terminal velocity at something lower than what the actual terminal velocity should be. Is there anyway to do this?



Before I switched to the PhysicsSystem I was using the formula



       acceleration  = force/mass + terminalVelocityConstant*velocityCurrent



By adjusting the terminalVelocityConstant I could keep the ships top speed at a reasonable level but still allow it to accelerate quickly.

The second problem involves ODE being too realistic. Right now the terminal velocity of my ship is way too high. I want it to have a nice zippy acceleration but I want to cap the terminal velocity at something lower than what the actual terminal velocity should be. Is there anyway to do this?


As a matter of fact, yes there is. There are two functions that are going to become your new best friends:

Vector3f velocity = somePhysicsObject.getLinearVelocity();
somePhysicsObject.setLinearVelocity(Vector3f);

Basically, you obtain the velocity, see if its above a threshold, and then set it at that threshold if its above it. However, there is one catch. The above methods return a directional vector. Ie. the speed and a direction both combined into one...

So you really need some maths trickery to get the speed from the direction. Basically (and i haven't tested this btw), you need to keep two copies, first the normalised vector (which is purely the direction) and the actual velocity vector.

Now divide the velocity vector by the directional vector and obtain the distance on that new vector. And that should be your speed. Step two is to cap that speed, multiply the directional vector by that and set that as your linearVelocity vector.

Im not sure about the divide part, it could be subtract, i'l have to induldge deeper but the idea is to obtain a scalar quantity from the directional vector, cap the scalar and multiply the directional back by that scalar to cap the velocity.

For your rotation problem, im afraid your going to have to either show me some of your source, or induldge it the explanation abit deeper. Also, have you tried "synchToGraphical(true)"? because that means you are syncing the ode counter part with the jme...and thats what you want isn't?

Anyway, keep me updated, im interested! :)

DP

Okay … for the rotation problem … here’s my rotation code.



    //shipObj is our PhysicsObject
    public void performAction(InputActionEvent evt) {
       Quaternion temp = new Quaternion(shipObj.getjMEGeometry().getLocalRotation());
       incr.loadIdentity();
        if (lockAxis == null) {
            incr.fromAxisAngle(shipObj.getjMEGeometry().getLocalRotation().getRotationColumn(1,
                    tempVa), -speed * evt.getTime());
        } else {
            incr.fromAxisAngle(lockAxis, -speed * evt.getTime());
        }
        shipObj.getjMEGeometry().getLocalRotation().fromRotationMatrix(
                incr.mult(shipObj.getjMEGeometry().getLocalRotation().toRotationMatrix(tempMa),
                        tempMb));
        shipObj.getjMEGeometry().getLocalRotation().normalize();
        shipObj.syncToGraphical(false);
     }



The above code is pretty much taken verbatim from Mojo's KeyNodeRotateRightAction class.


Here's my simpleInitGame() class



    protected void simpleInitGame() {
      // Set up the PhysicsWorld. It's set with default values, e.g. Earths
      // gravity.
      PhysicsWorld.create();
      PhysicsWorld.getInstance().setGravity(new Vector3f(0,0,0));
      
      // Here we tell the PhysicsWorld how many times per second we would like to
      // update it. It'll make the PhysicsWorlds internal timer govern the frequency
      // of update calls, thus obtaining frame rate independance. We set it to
      // 100 updates per second - the default is no restriction.
      PhysicsWorld.getInstance().setUpdateRate(100);
      
      // Here we tell the PhysicsWorld how much should change with each update.
      // A bigger value = faster animation. A step size of 2/UPS (updates/sec)
      // seem to give a rather nice simulation/result.
      PhysicsWorld.getInstance().setStepSize(2/100f);
      
      // Create a PhysicsObject from it. Note that we pass a mass by 1, thus making
      // it dynamic.
      shipObj = new PhysicsObject(ship, 50f);
      lightState.setEnabled(false);
       
       Map map = new Map(display);
       
      // Add the graphical representations to the rootNode. You can also get
      // a reference to it by calling PhysicsObject.getjMEGeometry().
       rootNode.attachChild(ship);
       rootNode.attachChild(map);
       
      // And the physical representations to the PhysicsWorld.
      PhysicsWorld.getInstance().addObject(shipObj);
      
      //Pass a reference to the input handlers for the ship so they can manipulate the geometry and forces
      shipMovementInput.init(shipObj);
    }



finally here's my update method


  protected final void update(float interpolation) {
     /** Recalculate the framerate. */
    timer.update();
      /** Update tpf to time per frame according to the Timer. */
    tpf = timer.getTimePerFrame();
   
      /** Check for key/mouse updates. */
    shipMovementInput.update(tpf);
    keyInput.update(tpf);
   
    //Update Physics Objects
    PhysicsWorld.getInstance().update();
   
    updateBuffer.setLength(0);
    updateBuffer.append("FPS: ").append((int)timer.getFrameRate()).append(" - ");
    updateBuffer.append(display.getRenderer().getStatistics(tempBuffer));
    /** Send the fps to our fps bar at the bottom. */
    fps.print(updateBuffer);

       
   //Move camera above the ship
   cam.setLocation(new Vector3f(ship.getLocalTranslation().x, 40, ship.getLocalTranslation().z));
   
    /** Update controllers/render states/transforms/bounds for rootNode. */
    rootNode.updateGeometricState(tpf, true);
   
    //Checks to see if any keys have been pressed in the key binding manager
    checkKeyBindingManager();

  }



Changing to synchToGraphical(true) isn't what I want since that will reset all the forces acting on the ship. That means whenever you turn, your ship screeches to a halt. With the current terminal velocity being seemingly close to the speed of light if you're gonna turn you'd better have your seat belt on. ;)

I'll give your suggestion for the terminal velocity a shot and will be sure to let you know how it goes.

By the way ... great work with the Physics stuff. Even with the problems it's been a breeze to use so far and my code will be much cleaner. [/code]

thanks, its glad to know that some other people are liking it! It gives a good moral boost to continue doing this… :slight_smile:



Anyways, about your rotational problem, i think I have found our little problem! The “syncToGraphical(boolean)” method was only really intended for fixed objects, such as walls…etc. But a new need to sync dynamic objects have risen (thanks to you ofcourse) and i will change the code to suit.



So ive gone ahead and compiled a special jar just for you. Grab it here



I haven’t tested the fix (because its 1 in the morning here), if this doesn’t work, i’l look deeper.



But thanks for brining this issue up. The only way we can progress is for our users to complain!



Edit: I should really start to learn how to spell, its getting ridiculous!



DP

wow … you’re awesome DP!!!



Thanks so much… I’ll be giving this is a shot right after dinner.

just replace the old jar by the new jar and make sure to refresh eclipse.



If you are using any of the constructors of PhysicsObject which takes a boolean as a value, just remove the boolean value, it will sort itself out now automagically…



DP

Works like a charm … thanks!!!

glad to hear that. Now i can go to sleep! Hurray!



If you find any more bugs, please let me know (me or per) and we’l get em fixed asap!



DP

This is kind of an old thread but I just got back to it. The whole terminal velocity this is a bigger problem that I thought.



If you simply check to see if your ship is going at a certain speed or not and then “cap” the speed by setting the current speed to be your cap then your ship will stop responding after you reach the cap.



So if you’re moving in a straight line to the left and reach the terminal velocity then turn your ship to face in the opposite direction and try to accelerate you can’t because you’re “stuck” at the terminal velocity.



I talked to my physics major friend and he said the correct way to do it is to use the following as your acceleration equation and adjust the terminal velocity constant.


acceleration  = force/mass + terminalVelocityConstant*velocityCurrent



Unfortunately now that I'm using ODE and the Physics system I can't use that formula anymore (which worked way back when I did my own simple 2d physics for response).

Any idea if ODE has a way to set a terminal velocity?

Umm, how are you moving the ship?



If you are using forces, then you can multiply the force by a scalar value which is k + (1/speed).



Ofcourse the speed can’t be 0, but this means that when your at a stop, it will accelerate alot quicker and when you are going fast, the force being applied onto the ship isn’t so great, so it will go to a nice steady pace.



k is there as a fudge factor, if you simply just have it as 1/speed, then your ship will have nearly no force on it when its going really fast. So just add a little.



Try that and see what the results are. If not, then i’l implement you something when I get home…



DP

Howbout multiplying your ship’s velocity with a constant < 1?



E.g something like this worked for me a while back:


private static final float AIR_RESISTANCE = 0.995f;

void applyAirResistance() {
      obj.setLinearVelocity(obj.getLinearVelocity().multLocal(AIR_RESISTANCE));
      obj.setAngularVelocity(obj.getAngularVelocity().multLocal(AIR_RESISTANCE));
}

but he wants to accelerate very quickly and wants his terminal velocity is small (relatively). So your constant has to decrease with the increase of speed. So 1/speed * k. Heh, same thing i suggested eh?



DP

Cool … I’ll give it a shot once I’m done with my classes today.

Doesn’t quite work.



For instace, if you build up some speed then turn your ship around and try to go in the opposite direction it’s really hard to change direction.



This is because you have a high speed so your force is getting lowered despite the fact that you want to change directions.



If you just apply a scalar factor to the force being applied to the ship then it’s not taking into consideration where the ship is trying to turn.



I really think this has to be done at the acceleration level when you are doing the computation there and it has to be done for each component seperately.



I don’t know if ODE lets you fiddle with that though.