我正在努力创建一个3D世界,我正在寻找帮助平滑我的鼠标控件以更像“FPS相机”(即:看起来鼠标在屏幕上的位置)
由于某种原因,我无法找到我的代码不好的地方..对于我来说,如果有意义的话,相机似乎是绕着一个支点移动而不仅仅是在它的轴上..
这是我的代码:
public class World3D extends Application {
private boolean forward, backward, left, right, vertControl;
private double mouX, mouY, oldX, oldY , deltaX, deltaY;
private final PerspectiveCamera camera = new PerspectiveCamera();
final Xform cameraXform = new Xform();
final Xform cameraXform2 = new Xform();
final Xform cameraXform3 = new Xform();
final double cameraDistance = 450;
final Group root = new Group();
final Group world = new Group();
@Override
public void start(Stage primaryStage) {
root.getChildren().add(world);
world.getChildren().add(cameraXform);
cameraXform.getChildren().add(cameraXform2);
cameraXform2.getChildren().add(cameraXform3);
cameraXform3.getChildren().add(camera);
cameraXform3.setRotateZ(180.0);
camera.setFarClip(100000.0D);
camera.setNearClip(0.1D);
cameraXform.ry.setAngle(320.0);
cameraXform.rx.setAngle(40);
cameraXform.setTranslateZ(-800.0D);
// sample skybox images
//http://www.zfight.com/misc/images/textures/envmaps/grimmnight_large.jpg
//http://www.zfight.com/misc/images/textures/envmaps/stormydays_large.jpg
//http://www.zfight.com/misc/images/textures/envmaps/miramar_large.jpg
//http://www.zfight.com/misc/images/textures/envmaps/interstellar_large.jpg
//http://www.zfight.com/misc/images/textures/envmaps/violentdays_large.jpg
SkyBox skyBox = new SkyBox(new Image("http://www.zfight.com/misc/images/textures/envmaps/violentdays_large.jpg"));
world.getChildren().add(skyBox);
Scene scene = new Scene(root, 1024, 768, true);
scene.setCamera(camera);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.setFullScreen(true);
primaryStage.show();
handleMouse(scene);
handleKeyboard(scene);
AnimationTimer timer = new AnimationTimer() {
@Override
public void handle(long l) {
if(forward && !vertControl){
cameraXform.setTranslateZ(cameraXform.getTranslateZ() + 2.0D);
}if(backward && !vertControl){
cameraXform.setTranslateZ(cameraXform.getTranslateZ() - 2.0D);
}if(left){
cameraXform.setTranslateX(cameraXform.getTranslateX() - 2.0D);
}if(right){
cameraXform.setTranslateX(cameraXform.getTranslateX() + 2.0D);
}
if(vertControl && forward){
cameraXform.setTranslateY(cameraXform.getTranslateY() - 2.0D);
}
if(vertControl && backward){
cameraXform.setTranslateY(cameraXform.getTranslateY() + 2.0D);
}
}
};
timer.start();
loadAPlanet();
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be
* launched through deployment artifacts, e.g., in IDEs with limited FX
* support. NetBeans ignores main().
*
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
private void handleKeyboard(Scene scene){
scene.setOnKeyPressed((KeyEvent t) -> {
switch(t.getCode()){
case W:// forward like fps
forward = true;
break;
case S: // backward
backward = true;
break;
case A: // left
left = true;
break;
case D: // right
right = true;
break;
case SPACE: // can go up and down
vertControl = true;
break;
}
});
scene.setOnKeyReleased((KeyEvent t) -> {
switch(t.getCode()){
case W:// forward like fps
forward = false;
break;
case S: // backward
backward = false;
break;
case A: // left
left = false;
break;
case D: // right
right = false;
break;
case SPACE: // can go up and down
vertControl = false;
break;
}
});
}
private void handleMouse(Scene scene){
scene.setOnMouseMoved((MouseEvent t) -> {
oldX = mouX;
oldY = mouY;
mouX = t.getSceneX();
mouY = t.getSceneY();
deltaX = (mouX - oldX);
deltaY = (mouY - oldY);
double modifier = 3.0;
double modifierFactor = 0.1;
if (t.isControlDown()) {
modifier = 0.1;
}
if (t.isShiftDown()) {
modifier = 10.0;
}
cameraXform.ry.setAngle(cameraXform.ry.getAngle() + deltaX * modifierFactor * modifier * 2.0); // +
cameraXform.rx.setAngle(cameraXform.rx.getAngle() + deltaY * modifierFactor * modifier * 2.0);
});
}
private void loadAPlanet(){
Sphere s = new Sphere();
PhongMaterial mat = new PhongMaterial();
//mat.setDiffuseMap(new Image("http://www.zfight.com/misc/images/textures/envmaps/interstellar_large.jpg"));
s.setMaterial(mat);
s.setDrawMode(DrawMode.LINE);
s.setRadius(150);
s.setTranslateX(camera.getTranslateX());
s.setTranslateZ(camera.getTranslateZ() + 500);
world.getChildren().add(s);
}
}
和我的SkyBox
public class SkyBox extends Group {
private final ObservableIntegerArray faces = FXCollections.observableIntegerArray();
private final ObservableFloatArray texCoords = FXCollections.observableFloatArray();
private final ObservableFloatArray points = FXCollections.observableFloatArray();
private final double WIDTH, HEIGHT, DEPTH;
private TriangleMesh cube;
private MeshView skyBox;
private float x0, x1, x2, x3, x4, y0, y1, y2, y3;
private Image texImg;
public SkyBox(Image diff){
this(20000,20000,20000, diff);
}
private SkyBox(double w, double h, double d, Image diffMap) {
this.WIDTH = w;
this.HEIGHT = h;
this.DEPTH = d;
this.cube = new TriangleMesh();
this.skyBox = new MeshView();
this.texImg = diffMap;
PhongMaterial mat = new PhongMaterial();
mat.setSpecularColor(Color.TRANSPARENT);
mat.setDiffuseMap(texImg);
this.calculatePoints();
this.calculateTexCoords();
this.calculateFaces();
this.skyBox.setMesh(cube);
this.skyBox.setMaterial(mat);
this.skyBox.setCullFace(CullFace.NONE);
AmbientLight light = new AmbientLight();
light.setTranslateX(skyBox.getTranslateX() + (WIDTH / 2));
light.setTranslateY(skyBox.getTranslateY() + (HEIGHT / 2));
light.setTranslateZ(skyBox.getTranslateZ() + (DEPTH / 2));
this.getChildren().addAll(skyBox, light);
}
private void calculatePoints() {
float hw = (float) WIDTH / 2f;
float hh = (float) HEIGHT / 2f;
float hd = (float) DEPTH / 2f;
points.addAll(
hw, hh, hd,
hw, hh, -hd,
hw, -hh, hd,
hw, -hh, -hd,
-hw, hh, hd,
-hw, hh, -hd,
-hw, -hh, hd,
-hw, -hh, -hd
);
cube.getPoints().addAll(points);
}
private void calculateFaces() {
faces.addAll(
0, 10, 2, 5, 1, 9,
2, 5, 3, 4, 1, 9,
4, 7, 5, 8, 6, 2,
6, 2, 5, 8, 7, 3,
0, 13, 1, 9, 4, 12,
4, 12, 1, 9, 5, 8,
2, 1, 6, 0, 3, 4,
3, 4, 6, 0, 7, 3,
0, 10, 4, 11, 2, 5,
2, 5, 4, 11, 6, 6,
1, 9, 3, 4, 5, 8,
5, 8, 3, 4, 7, 3
);
cube.getFaces().addAll(faces);
}
private void calculateTexCoords() {
x0 = 0f; x1 = 1 / 4f; x2 = 2 / 4f; x3 = 3 / 4f; x4 = 1f;
y0 = 0f; y1 = 1 /3f; y2 = 2 / 3f; y3 = 1f;
//x4 = 0; x3 = iw * 0.25f; x2 = iw / 2.0f; x1 = iw * 0.75f; x0 = iw;
//y3 = 0; y2 = ih * 0.33f; y1 = ih * 0.66f; y0 = ih;
texCoords.addAll(
(x1 + 0.001f), (y0 + 0.001f),
(x2 - 0.001f), y0,
(x0), (y1 + 0.001f),
(x1 + 0.001f), (y1 + 0.001f),
(x2 - 0.001f), (y1 + 0.001f),
x3, (y1 + 0.001f),
(x4), (y1 + 0.001f),
(x0), (y2 - 0.001f),
(x1 + 0.001f), (y2 - 0.001f),
x2, (y2 - 0.001f),
x3, (y2 - 0.001f),
(x4), (y2 - 0.001f),
(x1 + 0.001f), (y3 - 0.001f),
x2, (y3 - 0.001f)
);
cube.getTexCoords().addAll(texCoords);
}
public double getWidth() {
return WIDTH;
}
public double getHeight() {
return HEIGHT;
}
public double getDepth() {
return DEPTH;
}
}
和Xform
import javafx.scene.Group;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Translate;
public class Xform extends Group {
public enum RotateOrder {
XYZ, XZY, YXZ, YZX, ZXY, ZYX
}
public Translate t = new Translate();
public Translate p = new Translate();
public Translate ip = new Translate();
public Rotate rx = new Rotate();
{ rx.setAxis(Rotate.X_AXIS); }
public Rotate ry = new Rotate();
{ ry.setAxis(Rotate.Y_AXIS); }
public Rotate rz = new Rotate();
{ rz.setAxis(Rotate.Z_AXIS); }
public Scale s = new Scale();
public Xform() {
super();
getTransforms().addAll(t, rz, ry, rx, s);
}
public Xform(RotateOrder rotateOrder) {
super();
// choose the order of rotations based on the rotateOrder
switch (rotateOrder) {
case XYZ:
getTransforms().addAll(t, p, rz, ry, rx, s, ip);
break;
case XZY:
getTransforms().addAll(t, p, ry, rz, rx, s, ip);
break;
case YXZ:
getTransforms().addAll(t, p, rz, rx, ry, s, ip);
break;
case YZX:
getTransforms().addAll(t, p, rx, rz, ry, s, ip); // For Camera
break;
case ZXY:
getTransforms().addAll(t, p, ry, rx, rz, s, ip);
break;
case ZYX:
getTransforms().addAll(t, p, rx, ry, rz, s, ip);
break;
}
}
public void setTranslate(double x, double y, double z) {
t.setX(x);
t.setY(y);
t.setZ(z);
}
public void setTranslate(double x, double y) {
t.setX(x);
t.setY(y);
}
// Cannot override these methods as they are final:
// public void setTranslateX(double x) { t.setX(x); }
// public void setTranslateY(double y) { t.setY(y); }
// public void setTranslateZ(double z) { t.setZ(z); }
// Use these methods instead:
public void setTx(double x) { t.setX(x); }
public void setTy(double y) { t.setY(y); }
public void setTz(double z) { t.setZ(z); }
public void setRotate(double x, double y, double z) {
rx.setAngle(x);
ry.setAngle(y);
rz.setAngle(z);
}
public void setRotateX(double x) { rx.setAngle(x); }
public void setRotateY(double y) { ry.setAngle(y); }
public void setRotateZ(double z) { rz.setAngle(z); }
public void setRx(double x) { rx.setAngle(x); }
public void setRy(double y) { ry.setAngle(y); }
public void setRz(double z) { rz.setAngle(z); }
public void setScale(double scaleFactor) {
s.setX(scaleFactor);
s.setY(scaleFactor);
s.setZ(scaleFactor);
}
public void setScale(double x, double y, double z) {
s.setX(x);
s.setY(y);
s.setZ(z);
}
// Cannot override these methods as they are final:
// public void setScaleX(double x) { s.setX(x); }
// public void setScaleY(double y) { s.setY(y); }
// public void setScaleZ(double z) { s.setZ(z); }
// Use these methods instead:
public void setSx(double x) { s.setX(x); }
public void setSy(double y) { s.setY(y); }
public void setSz(double z) { s.setZ(z); }
public void setPivot(double x, double y, double z) {
p.setX(x);
p.setY(y);
p.setZ(z);
ip.setX(-x);
ip.setY(-y);
ip.setZ(-z);
}
public void reset() {
t.setX(0.0);
t.setY(0.0);
t.setZ(0.0);
rx.setAngle(0.0);
ry.setAngle(0.0);
rz.setAngle(0.0);
s.setX(1.0);
s.setY(1.0);
s.setZ(1.0);
p.setX(0.0);
p.setY(0.0);
p.setZ(0.0);
ip.setX(0.0);
ip.setY(0.0);
ip.setZ(0.0);
}
public void resetTSP() {
t.setX(0.0);
t.setY(0.0);
t.setZ(0.0);
s.setX(1.0);
s.setY(1.0);
s.setZ(1.0);
p.setX(0.0);
p.setY(0.0);
p.setZ(0.0);
ip.setX(0.0);
ip.setY(0.0);
ip.setZ(0.0);
}
}
任何帮助将不胜感激 (球体在世界上仅用于相机位置参考)