Based on some code vitek posted a while ago.
PViewer.receiver = my eventreceiver
PViewer.elapsedTime
Code: Select all
elapsedTime = 1000000 * (timer2 - timer1) * (0.000001f / 30f); // in secondstimer2 = milliseconds after you've done everything in the run loop
Some constants in PMain
Code: Select all
public static final short CAMERA_MAX_ZOOM_DISTANCE = 1000;
public static final short CAMERA_MIN_ZOOM_DISTANCE = 90;
public static final float CAMERA_LINEAR_VELOCITY = 5f; // zoom speed
public static final float CAMERA_ANGULAR_VELOCITY = 0.5f; // camera turn speed on mouse dragCode: Select all
class CameraTask {
private float radius = 400f;
private float theta = 180f;
private float phi = 60f;
private float radiusVelocity = 0;
private float thetaVelocity = 0;
private float phiVelocity = 0;
private final float thetaFriction = 1.3f;
private final float thetaMaxVelocity = 40;
private final float phiFriction = 1.3f;
private final float phiMaxVelocity = 40;
private final float radiusFriction = 1.3f;
private final float radiusMaxVelocity = 50;
private ArrayList<Float> radiusAverages = new ArrayList<Float>(0);
private ArrayList<Float> thetaAverages = new ArrayList<Float>(0);
private ArrayList<Float> phiAverages = new ArrayList<Float>(0);
private final int averageSampleSize = 10; // Lower to make it less smooth, Higher to make it more smooth (but then it starts to jump around a lot)
public CameraTask() {
for (int a = 0; a < averageSampleSize; a++) {
radiusAverages.add(0f);
thetaAverages.add(0f);
phiAverages.add(0f);
}
}
public void run() {
if (theta > 360 || theta < 0) theta %= 360;
/*
* Zoom in/out
*/
if (PViewer.receiver.getLastWheelMovement() > 0) { // zoom in
if (radiusVelocity > -radiusMaxVelocity)
radiusVelocity -= PMain.CAMERA_LINEAR_VELOCITY * PViewer.receiver.getLastWheelMovement() * PViewer.elapsedTime * 10;
PViewer.receiver.setLastWheelMovement(0);
} else if (PViewer.receiver.getLastWheelMovement() < 0) { // zoom out
if (radiusVelocity < radiusMaxVelocity)
radiusVelocity -= PMain.CAMERA_LINEAR_VELOCITY * PViewer.receiver.getLastWheelMovement() * PViewer.elapsedTime * 10;
PViewer.receiver.setLastWheelMovement(0);
} else {
// if the mouse isn't moving then apply friction
if (radiusVelocity < -0.1f || radiusVelocity > 0.1f)
radiusVelocity = radiusVelocity / radiusFriction;
else
radiusVelocity = 0;
}
/*
* Rotate and translate left/right
*/
if (PViewer.receiver.getCursorDelta().getX() > 0) { // rotate clockwise
if (PViewer.receiver.isMouseDownL()) {
if (thetaVelocity < thetaMaxVelocity)
thetaVelocity += PMain.CAMERA_ANGULAR_VELOCITY * PViewer.receiver.getCursorDelta().getX() * PViewer.elapsedTime;
}
PViewer.receiver.getCursorDelta().setX(0);
} else if (PViewer.receiver.getCursorDelta().getX() < 0) { // rotate anticlockwise
if (PViewer.receiver.isMouseDownL()) {
if (thetaVelocity > -thetaMaxVelocity)
thetaVelocity += PMain.CAMERA_ANGULAR_VELOCITY * PViewer.receiver.getCursorDelta().getX() * PViewer.elapsedTime;
}
PViewer.receiver.getCursorDelta().setX(0);
} else {
if (thetaVelocity < -0.1f || thetaVelocity > 0.1f)
thetaVelocity = thetaVelocity / thetaFriction;
else
thetaVelocity = 0;
}
/*
* Rotate and translate up/down
*/
if (PViewer.receiver.getCursorDelta().getY() > 0) { // rotate up
if (PViewer.receiver.isMouseDownL()) {
if (phiVelocity < phiMaxVelocity)
phiVelocity -= PMain.CAMERA_ANGULAR_VELOCITY * PViewer.receiver.getCursorDelta().getY() * PViewer.elapsedTime;
}
PViewer.receiver.getCursorDelta().setY(0);
} else if (PViewer.receiver.getCursorDelta().getY() < 0) { // rotate down
if (PViewer.receiver.isMouseDownL()) {
if (phiVelocity < phiMaxVelocity)
phiVelocity -= PMain.CAMERA_ANGULAR_VELOCITY * PViewer.receiver.getCursorDelta().getY() * PViewer.elapsedTime;
}
PViewer.receiver.getCursorDelta().setY(0);
} else {
if (phiVelocity < -0.1f || phiVelocity > 0.1f)
phiVelocity = phiVelocity / phiFriction;
else
phiVelocity = 0;
}
if (thetaVelocity >= thetaMaxVelocity) thetaVelocity = thetaMaxVelocity;
else if (thetaVelocity <= -thetaMaxVelocity) thetaVelocity = -thetaMaxVelocity;
if (phiVelocity >= phiMaxVelocity) phiVelocity = phiMaxVelocity;
else if (phiVelocity <= -phiMaxVelocity) phiVelocity = -phiMaxVelocity;
if (radiusVelocity >= radiusMaxVelocity) radiusVelocity = radiusMaxVelocity;
else if (radiusVelocity <= -radiusMaxVelocity) radiusVelocity = -radiusMaxVelocity;
radiusAverages.remove(0);
radiusAverages.add(radiusVelocity);
thetaAverages.remove(0);
thetaAverages.add(thetaVelocity);
phiAverages.remove(0);
phiAverages.add(phiVelocity);
float radiusAverageVelocity = 0, thetaAverageVelocity = 0, phiAverageVelocity = 0;
for (int a = 0; a < averageSampleSize; a++) {
radiusAverageVelocity += radiusAverages.get(a);
thetaAverageVelocity += thetaAverages.get(a);
phiAverageVelocity += phiAverages.get(a);
}
radiusAverageVelocity /= averageSampleSize;
thetaAverageVelocity /= averageSampleSize;
phiAverageVelocity /= averageSampleSize;
if (radiusAverageVelocity != 0) radius += radiusAverageVelocity;
if (thetaAverageVelocity != 0) theta += thetaAverageVelocity;
if (phiAverageVelocity != 0) phi += phiAverageVelocity;
// min zoom
if (radius < PMain.CAMERA_MIN_ZOOM_DISTANCE)
radius = PMain.CAMERA_MIN_ZOOM_DISTANCE;
else if (radius > PMain.CAMERA_MAX_ZOOM_DISTANCE)
radius = PMain.CAMERA_MAX_ZOOM_DISTANCE;
/*
* lame ass gimble lock prevention. if you don't want to do this
* you need to adjust the up vector of the camera so it never is
* parallel to the look at vector
*/
if (phi < 1f)
phi = 1f;
else if (179f < phi)
phi = 179f;
float sinOfPhi = (float)Math.sin(VF.D2R(phi));
float cosOfPhi = (float)Math.cos(VF.D2R(phi));
float sinOfTheta = (float)Math.sin(VF.D2R(theta));
float cosOfTheta = (float)Math.cos(VF.D2R(theta));
vector3df offset = new vector3df();
offset.setX(radius * sinOfTheta * sinOfPhi);
offset.setY(radius * cosOfPhi);
offset.setZ(radius * cosOfTheta * sinOfPhi);
// camera is a child of the cube, so our offset is actually
// the position of the camera
PViewer.camera.setPosition(offset);
PViewer.camera.updateAbsolutePosition();
offset.delete();
}
}