Problems working out an auto-leveling routine

Hey guys. I need some inspiration on how to level out a model to the xz plane. I’ve got it… sorta… working with this.



maxRotation is the maximum force allowed to be applied to the spatial for turning.



turnUp, turnDown, rollRight, rollLeft all employ the torque to turn the model.



[java]public void levelUsOut() {



float xRot;

float zRot;



float[] angles = new float[3];



this.getWorldRotation().toAngles(angles);



xRot = angles[0] * FastMath.RAD_TO_DEG;

zRot = angles[2] * FastMath.RAD_TO_DEG;



miscString = “xRot:” + xRot + " zRot:" + zRot;



if (xRot > 0 && xRot < 90) {

//The nose is down



turnUp(maxRotation * (xRot/100));

} else if (xRot < 0 && xRot > -90) {

//The nose is up

turnDown(maxRotation * -(xRot/100));

}



if (zRot > 0 && zRot < 90) {

//Rolling to starboard

rollLeft(maxRotation * (zRot/100));

} else if (zRot < 0 && zRot > -90) {

//Rolling to port

rollRight(maxRotation * -(zRot/100));

}



}[/java]



This works great when you put the nose of the craft down it’ll push it back up level as you please. BUT heaven forbid if your model slightly rolls and your nose is down because whoever is at the helm of your ship then has clearly been drinking heavily. The ship ends up weaving and twisting in all sorts of odd directions but eventually it does level itself out.



I have tried static roll values and it does the same thing but slower. My idea with the little math there was that when you get up to 90 degrees your ship will be pushing back at 90% of the total thrust allowed. I’m debating about just not allowing a user to exceed +/- 90 degrees which is why that case isn’t covered yet.



Anyways any thoughts or ideas? I was also debating about handling the roll to right or left statically without physics but that could get weird if the ship collides with something.

Assuming i understand correctly, then perhaps this will help:

http://hub.jmonkeyengine.org/groups/user-code-projects/forum/topic/jme-simple-examples-project/?action=rpx_token&topic_page=3&num=15#post-186551



What you need to do is, find the direction vector you want your ship to be pointing in the XZ plane. Whether its based on the cam direction or something im not sure (based on what you said). Then from this you need to apply 3 different torques in all the X, Y, Z axes



These are found by doing a cross product between the new direction of each axis (currentRotation * Global Axis), and the desired direction vector

Hmmm. I think I follow what you mean. I’ll give it a whirl.



Here’s a better explanation of what I’m trying to do. Basically I have a space ship that I can control with the arrow keys for pitch and yaw. When I let go of these what I’d like is for the ship to automatically level itself out to be in alignment to the xz plane keeping it’s bearing (y rotation). So my theory was that applying torque to the x and z axis that the ship would level itself while maintaining any rotation it has around the y axis.



Anyways like I said I’ll give it a whirl and see what happens. Thanks!

Ok. Using your link there and rereading through the math for dummies section for the umpteenth time I think what I came up with will work with some tweaking (It’s working now but under certain circumstances the ship weaves like a drunkard).



[java]

Vector3f fixer = new Vector3f(-shipControl.getPhysicsRotation().getX(), 0f, -shipControl.getPhysicsRotation().getZ());



shipControl.applyTorque(fixer.mult(25f));

[/java]



So basically I take whatever rotation the ship currently has about the axis that I want to counter act, inverse them in a new vector then use that as my torque. Or do you foresee some serious issues with this going forward?

@thecyberbob said:
Ok. Using your link there and rereading through the math for dummies section for the umpteenth time I think what I came up with will work with some tweaking (It's working now but under certain circumstances the ship weaves like a drunkard).

[java]
Vector3f fixer = new Vector3f(-shipControl.getPhysicsRotation().getX(), 0f, -shipControl.getPhysicsRotation().getZ());

shipControl.applyTorque(fixer.mult(25f));
[/java]

So basically I take whatever rotation the ship currently has about the axis that I want to counter act, inverse them in a new vector then use that as my torque. Or do you foresee some serious issues with this going forward?


You may be misunderstanding what a Quaternion is. The values are magic. You can't just take the X value and expect it to mean anything useful, ie: it is NOT rotation about the X axis. It could be kind of a coincidence that it works at all.

Do you support full 6 degree rotation or do you keep a consistent y up like an FPS shooter? I guess if you have a consistent "plane" that you are trying to level to then you must restrict what up is. What does roll mean in that situation? Or is rolling just an effect?

In other words, if the ship is rolled 45 degrees and the ship "pulls up"... what happens?

@thecyberbob



I made a test to auto orient it to the XZ plane on any rotation, hopefully its what you wanted.



[java]package com.mmm.util.test;



import com.jme3.app.SimpleApplication;

import com.jme3.bullet.BulletAppState;

import com.jme3.bullet.PhysicsSpace;

import com.jme3.bullet.PhysicsTickListener;

import com.jme3.bullet.control.RigidBodyControl;

import com.jme3.material.Material;

import com.jme3.math.Vector3f;

import com.jme3.scene.Geometry;

import com.jme3.scene.shape.Box;



public class NewPhysics extends SimpleApplication implements PhysicsTickListener {



public static void main(String[] args) {

new NewPhysics().start();

}

private BulletAppState bulletAppState;

private Geometry geometry;



@Override

public void simpleInitApp() {

bulletAppState = new BulletAppState();

stateManager.attach(bulletAppState);



Box box = new Box(Vector3f.ZERO, new Vector3f(1, 1, 1));

geometry = new Geometry(“name”, box);

Material mat = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);

geometry.setMaterial(mat);

rootNode.attachChild(geometry);

geometry.rotate(-0.5f, -0.5f, -0.7f);

cam.setLocation(new Vector3f(3, 0, 0));

cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);



geometry.addControl(new RigidBodyControl());

bulletAppState.getPhysicsSpace().add(geometry);



bulletAppState.getPhysicsSpace().setGravity(Vector3f.ZERO);

bulletAppState.getPhysicsSpace().addTickListener(this);



}



public void prePhysicsTick(PhysicsSpace space, float tpf) {

RigidBodyControl control = geometry.getControl(RigidBodyControl.class);

control.setAngularVelocity(Vector3f.ZERO);



if (Vector3f.UNIT_Y.angleBetween(control.getPhysicsRotation().mult(Vector3f.UNIT_Y)) < 0.03f) {

return;

}



Vector3f spatialY = control.getPhysicsRotation().mult(Vector3f.UNIT_Y);

Vector3f cross = spatialY.crossLocal(Vector3f.UNIT_Y).normalizeLocal();

control.applyTorque(cross);

}



public void physicsTick(PhysicsSpace space, float tpf) {

}

}[/java]

Thanks wezrule, I was trying to get “auto levelling” working also but got my head in a knot trying to figure out how to go from local orientation to torque in world space. Will give this a spin when I’m on my dev computer next time.

@pspeed said:
In other words, if the ship is rolled 45 degrees and the ship "pulls up"... what happens?


Initially pulling up works fine. After you've turned a bit it does get further and further off of a straight "pull up". I was hoping my understanding of why that happens would get better once I figured out this leveling out business but it's just left me more confused as you can see. :(

@wezrule said:
I'll give that a shot! Thanks!

@wezrule said:



Awesome. That worked. I modified it a bit so it’d keep some of the fluid movement I’m kinda aiming for. Basically removed this line:



[java]

control.setAngularVelocity(Vector3f.ZERO);

[/java]

@thecyberbob said:
Initially pulling up works fine. After you've turned a bit it does get further and further off of a straight "pull up". I was hoping my understanding of why that happens would get better once I figured out this leveling out business but it's just left me more confused as you can see. :(


No. I meant what is it that you intend for it to do. I was just trying to understand what control scheme you had in mind. If this is essentially a 2.5D control system like in an FPS.

@pspeed said:



Lets go with “guided 3D”. What I’m trying to achieve is the same sort of motion you see in say EVE Online or with Star Trek (games, series, movies, etc). The whole you can fly in pretty much any direction but when you stop moving your ship then slowly rotates back to the same plane everyone else does (How else do the ships in Star Trek always seem to line up with each other? Who decided which way was “up”?).



In EVE Online specifically you seem to be limited to turning up or down 90 degree’s max but generally your ship will always align itself back to the xz plane at some point.



Not sure if that describes what I want to do or not better. My end goal is to make a game that is more space ships in space less star fighters (X-Wing Fighters whatever) in space.