3D场景相机缩放沿Y轴而非Z轴异常问题求助
3D相机缩放时Box偏移问题解决
我在原点放置了一个3D Box,通过移动相机而非旋转Box实现环绕观察。鼠标拖拽控制相机移动功能正常,但缩放功能不符合预期:当相机沿Y轴移动后,执行缩放操作时,Box会沿Y轴移动而非Z轴。
初始Box状态
鼠标拖拽上下移动后的Box状态
缩放后的Box状态
可见放大时Box向下偏移,缩小时向上偏移。我认为需固定相机缩放参考点,请问如何解决该问题?以下是相关代码:
public Main3D() { root = new HBox(); root.setAlignment(Pos.CENTER); xRotate = new Rotate(0, Rotate.X_AXIS); yRotate = new Rotate(0, Rotate.Y_AXIS); currAngleX = new SimpleDoubleProperty(0); currAngleY = new SimpleDoubleProperty(0); currAngleZ = new SimpleDoubleProperty(0); truckMaterial = new PhongMaterial(); } private void initiate3dSphereScene() { // Create the container/truck truck = new Box(Truck.WIDTH, Truck.HEIGHT, Truck.DEPTH); truckMaterial.setDiffuseColor(Color.SILVER.deriveColor(.3, .3, .4, .3)); truck.setMaterial(truckMaterial); group = new Group(); group.getChildren().add(truck); mainScene = new SubScene(group, SCREEN_WIDTH * .75, SCREEN_HEIGHT, true, SceneAntialiasing.BALANCED); mainScene.setFill(Color.SILVER); // Set up the camera camera = new PerspectiveCamera(true); camera.getTransforms().addAll(xRotate, yRotate, new Translate(0, 0, -40)); camera.setNearClip(1); camera.setFarClip(100000); mainScene.setCamera(camera); initiateMouseControl(); } private void initiateMouseControl() { xRotate.angleProperty().bind(currAngleX); yRotate.angleProperty().bind(currAngleY); mainScene.setOnMousePressed(mouseEvent -> { currX = mouseEvent.getSceneX(); currY = mouseEvent.getSceneY(); newX = currAngleX.get(); newY = currAngleY.get(); }); mainScene.setOnMouseDragged(mouseEvent -> { currAngleX.set(newX + (currY - mouseEvent.getSceneY())); currAngleY.set(newY - (currX - mouseEvent.getSceneX())); }); mainScene.addEventHandler(ScrollEvent.SCROLL, event -> { double zoom = event.getDeltaY(); camera.translateZProperty().set(camera.getTranslateZ() + zoom / 10); camera.translateYProperty().set(currAngleY.get()); }); mainScene.setOnKeyPressed(KeyEvent -> { if (KeyEvent.getCode() == KeyCode.C) { camera.translateXProperty().set(0); camera.translateXProperty().set(0); camera.translateZProperty().set(-40); } }); }
问题原因及解决办法
问题1:错误设置相机Y轴平移
你的ScrollEvent处理代码里,错误地将camera.translateYProperty()设置为currAngleY.get(),这完全是多余操作,直接导致缩放时相机Y轴位置被强制修改,出现Box偏移。先删掉这一行代码。
问题2:缩放方向错误
直接修改camera.translateZ()是在全局坐标系下移动,但相机旋转后,自身的视线方向(局部Z轴)已经和全局Z轴不一致,所以沿全局Z轴移动会让相机偏离目标Box。正确的做法是让相机沿着自身的视线方向移动,这样不管怎么旋转,缩放都是朝向/远离Box的方向。
修改后的ScrollEvent处理代码:
mainScene.addEventHandler(ScrollEvent.SCROLL, event -> { double zoomSpeed = 1.0; // 可根据需求调整缩放速度 double zoomDelta = event.getDeltaY() * zoomSpeed / 10; // 获取相机的视线方向向量(局部Z轴转换到全局坐标系) Point3D direction = camera.getLocalToParentTransform().transform(new Point3D(0, 0, 1)); direction = direction.normalize(); // 标准化向量,保证移动距离一致 // 沿视线方向移动相机 camera.setTranslateX(camera.getTranslateX() + direction.getX() * zoomDelta); camera.setTranslateY(camera.getTranslateY() + direction.getY() * zoomDelta); camera.setTranslateZ(camera.getTranslateZ() + direction.getZ() * zoomDelta); });
问题3:重置相机代码的小错误
重置相机的代码里重复设置了translateX两次,应该补上translateY的重置,同时重置旋转角度:
mainScene.setOnKeyPressed(KeyEvent -> { if (KeyEvent.getCode() == KeyCode.C) { camera.setTranslateX(0); camera.setTranslateY(0); camera.setTranslateZ(-40); currAngleX.set(0); currAngleY.set(0); } });
这样修改后,缩放操作就会保持相机始终朝向Box移动,不会出现Y轴偏移的问题。
内容的提问来源于stack exchange,提问作者Hadi Ayoub
相关产品推荐
相关产品推荐

