You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

3D场景相机缩放沿Y轴而非Z轴异常问题求助

3D相机缩放时Box偏移问题解决

我在原点放置了一个3D Box,通过移动相机而非旋转Box实现环绕观察。鼠标拖拽控制相机移动功能正常,但缩放功能不符合预期:当相机沿Y轴移动后,执行缩放操作时,Box会沿Y轴移动而非Z轴。

初始Box状态
Initial Box

鼠标拖拽上下移动后的Box状态
Box after mouse dragging up and down

缩放后的Box状态
Box after zoom-in

可见放大时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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 04:31:24