Perhaps the rest of the TopView.java could give some insight as to what we’re trying to achieve with this camera:
[java]public class TopView extends AbstractAppState
{
private SimpleApplication sa;
private Node rootNode;
private Spatial ctl;
private InputManager im;
private Camera cam;
private float dist;
private Vector3f oldPos;
@Override public void initialize(AppStateManager stateManager, Application app)
{
super.initialize(stateManager, app);
// get stuff we need from the world
this.sa = (SimpleApplication) app;
rootNode = sa.getRootNode();
cam = sa.getCamera();
ctl = rootNode.getChild("cameraControl");
im = sa.getInputManager();
// set up the camera
sa.getFlyByCamera().setEnabled(false);
dist = 20f;
oldPos = ctl.getWorldTranslation();
rotateCamera(0.01f, 1, Vector3f.UNIT_X);
cam.lookAt(ctl.getWorldTranslation(), Vector3f.UNIT_Y);
// assign inputs for movement
im.addMapping("Fast", new KeyTrigger(KeyInput.KEY_LSHIFT), new KeyTrigger(KeyInput.KEY_RSHIFT));
im.addMapping("Forward", new KeyTrigger(KeyInput.KEY_W));
im.addMapping("Backward", new KeyTrigger(KeyInput.KEY_S));
im.addMapping("Left", new KeyTrigger(KeyInput.KEY_A));
im.addMapping("Right", new KeyTrigger(KeyInput.KEY_D));
im.addMapping("North", new KeyTrigger(KeyInput.KEY_UP));
im.addMapping("South", new KeyTrigger(KeyInput.KEY_DOWN));
im.addMapping("East", new KeyTrigger(KeyInput.KEY_RIGHT));
im.addMapping("West", new KeyTrigger(KeyInput.KEY_LEFT));
im.addListener(evt.digital, "Fast");
im.addListener(evt.analog, "Forward", "Backward", "Left", "Right", "North", "South", "East", "West");
// assign inputs for camera rotation
im.addMapping("Rotator",new KeyTrigger(KeyInput.KEY_LCONTROL), new MouseButtonTrigger(MouseInput.BUTTON_MIDDLE));
im.addMapping("Up", new MouseAxisTrigger(MouseInput.AXIS_Y, true));
im.addMapping("Down", new MouseAxisTrigger(MouseInput.AXIS_Y, false));
im.addMapping("RLeft", new MouseAxisTrigger(MouseInput.AXIS_X, false));
im.addMapping("RRight", new MouseAxisTrigger(MouseInput.AXIS_X, true));
im.addMapping("In", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, false));
im.addMapping("Out", new MouseAxisTrigger(MouseInput.AXIS_WHEEL, true));
im.addListener(evt.digital, "Rotator");
im.addListener(evt.analog, "Up", "Down", "RLeft", "RRight", "In", "Out");
}
@Override public void update(float tpf)
{
Vector3f pos = ctl.getWorldTranslation();
if ( oldPos.equals(pos) ) // only do this if we have moved
{
cam.lookAt(pos, Vector3f.UNIT_Y);
oldPos = pos;
}
}
@Override public void cleanup()
{
super.cleanup();
//TODO: clean up what you initialized in the initialize method,
//e.g. remove all spatials from rootNode
//this is called on the OpenGL thread after the AppState has been detached
}
private EventListener evt = new EventListener()
{
// simple state-tracking for the input system
boolean speedBtn = false;
boolean rotator = false;
@Override public void onInput(String name, float value, float tpf, float spd)
{
Vector3f pos = new Vector3f(0, 0, 0);
// simple state-tracking for the input system
if ( name.equals("Fast") ) { if ( value == 1 ) { speedBtn = true; } else { speedBtn = false; } }
if ( name.equals("Rotator") ) { if ( value == 1 ) { rotator = true; } else { rotator = false; } }
// go faster!
if ( speedBtn ) { spd = spd * 2; }
switch ( name )
{
// relative movement
case "Forward": pos = cam.getDirection(); pos.y = 0; break;
case "Backward": pos = cam.getDirection(); pos.y = 0; pos = pos.mult(-1); break;
case "Right": pos = cam.getLeft(); pos.y = 0; pos = pos.mult(-1); break;
case "Left": pos = cam.getLeft(); pos.y = 0; break;
// absolute movement
case "North": pos.z = + 1; break;
case "South": pos.z = - 1; break;
case "East": pos.x = - 1; break;
case "West": pos.x = + 1; break;
// camera distance from object
case "In": dist -= spd / 10; fixDist(); break;
case "Out": dist += spd / 10; fixDist(); break;
}
// update the controller and camera
pos = pos.mult(spd);
ctl.move(pos);
rotateCamera(0, tpf, Vector3f.ZERO);
// you spin me round
if ( !rotator ) { return; }
// camera rotators
switch ( name )
{
case "Up": rotateCamera(value, tpf, new Vector3f(1, 0, 1)); break;
case "Down": rotateCamera(-value, tpf, new Vector3f(1, 0, 1)); break;
case "RLeft": rotateCamera(-value, tpf, Vector3f.UNIT_Y); break;
case "RRight": rotateCamera(value, tpf, Vector3f.UNIT_Y); break;
}
}
};
protected void fixDist()
{
FastMath.clamp(dist, 5f, 50f);
}
protected void rotateCamera(float value, float tpf, Vector3f axis)
{
float rotationSpeed = 1000;
Matrix3f mat = new Matrix3f();
mat.fromAngleNormalAxis(rotationSpeed * value * tpf, axis);
Vector3f upDir = cam.getUp();
Vector3f leftDir = cam.getLeft();
Vector3f dir = cam.getDirection();
mat.mult(upDir, upDir);
mat.mult(leftDir, leftDir);
mat.mult(dir, dir);
Quaternion q = new Quaternion();
q.fromAxes(leftDir, upDir, dir);
q.normalizeLocal();
sa.getCamera().setAxes(q);
dir = cam.getDirection();
dir = dir.mult(dist);
Vector3f invDir = new Vector3f(-dir.x, -dir.y, -dir.z);
Vector3f position = invDir.add(ctl.getWorldTranslation());
position.y = FastMath.clamp(position.y, ctl.getWorldTranslation().y - 1, ctl.getWorldTranslation().y + dist + 1);
cam.setLocation(position);
cam.lookAt(ctl.getWorldTranslation(), Vector3f.UNIT_Y);
}
}[/java]
I do apologise for any trouble this may be causing.