JavaFX 8 Z-buffer问题

5

我的问题与JavaFX 3D中的Z-Buffer有关,在我的机器上似乎无法按预期工作。

我知道以下问题: 重叠形状...Z顺序...

然而,我已启用Z-Buffer,并且节点仍按添加到场景图的顺序渲染。

也许我缺少一些依赖项或其他东西吗?

我将发布代码,希望有人能帮助我。我正在创建一个将节点沿椭圆路径围绕另一个节点移动的过渡。

提前感谢您!

public class OrbitExp extends Application {
Group root = new Group();
Scene scene = new Scene(root, 800, 600, true, SceneAntialiasing.BALANCED);
PerspectiveCamera camera = new PerspectiveCamera();
@Override
public void start(Stage primaryStage) {
    root.setDepthTest(DepthTest.ENABLE); 
//Tried to set Depthtest explicitly. Assumed maybe it did not inherit:S
    System.out.println(
        "3D supported? " +
        Platform.isSupported(ConditionalFeature.SCENE3D)
    );    // returns true

    System.out.println("root z-buffer: " + root.getDepthTest());
    initCamera();
    Box 
            box1 = new Box(50,50,50),
            box2 = new Box(10,10,10);
    root.setTranslateX(scene.getWidth()/2);
    root.setTranslateY(scene.getHeight()/2);
    PhongMaterial 
            pmat = new PhongMaterial(Color.BLUE),
            pmat2 = new PhongMaterial(Color.RED);
    box1.setMaterial(pmat);
    box2.setMaterial(pmat2);
    scene.setFill(Color.LIGHTGREEN);
    root.getChildren().addAll(box1,box2);
    SequentialTransition sqt = orbit(box1, box2, 40, 40, Duration.seconds(3), 360);
    sqt.play();
    scene.setOnMouseClicked(click->{
        Node node = (Node)(click.getPickResult().getIntersectedNode());
        System.out.println("Tx: "+node.getTranslateX());
        System.out.println("Ty: "+node.getTranslateY());
        System.out.println("Tz: "+node.getTranslateZ());
    }); 
// just for debugging, but coords does seem to be alright
    primaryStage.setScene(scene);
    primaryStage.show();
}
public static void main(String[] args) {
    launch(args);
}
private void initCamera() {
    camera.setTranslateZ(-50);
    camera.setTranslateY(20);
    camera.setFarClip(5000);
    camera.setNearClip(0);
    scene.setCamera(camera);
}
SequentialTransition orbit(Node node1, Node node2,double a, double b, Duration totalDuration, int N) {
    SequentialTransition sqt = new SequentialTransition();
    Duration dur = new Duration(totalDuration.toMillis()*(1.0d/N));
    node2.setTranslateX(a+node1.getTranslateX());
    node2.setTranslateZ(node1.getTranslateZ());
    for (int i = 1; i < N; i++) {
        TranslateTransition tt = new TranslateTransition(dur, node2);
        double 
                angle = i*(360.0d/N),
                toX = (Math.cos(Math.toRadians(angle))*a)+node1.getTranslateX(),
                toZ = (Math.sin(Math.toRadians(angle))*b)+node1.getTranslateZ();
        tt.setToX(toX);
        tt.setToZ(toZ);
        tt.setInterpolator(Interpolator.LINEAR);
        sqt.getChildren().add(tt);
        System.out.println("angle = " + angle + "\nangle in rads: " + Math.toRadians(angle) + "\ntoX = " + toX + "\ntoZ = " + toZ);
    }
    sqt.setCycleCount(Timeline.INDEFINITE);
    return sqt;
}

这是我发表的第一篇帖子:)

1个回答

5
如果您使用矩形检查您提供的链接上的代码,深度缓冲区将正常工作。
将矩形更改为使用3D框也可以。
问题在于如何定义一个盒子相对于另一个盒子的旋转,因此我已经应用了一个旋转变换到红色盒子上,在蓝色盒子的中心设置了一个支点,并使用AnimationTimer修改该旋转的角度以创建“轨道”效果。
您甚至可以在大盒子上使用透明度(自8u60起)以看到其下面的小盒子。
private final Group shapes = new Group();
private long lastTimerCall;
private AnimationTimer timeline;

@Override
public void start(Stage stage) throws Exception {
    Scene scene = new Scene(createRotatingShapes(), 400, 300,
            true, SceneAntialiasing.BALANCED);
    scene.setFill(Color.LIGHTGREEN);
    final PerspectiveCamera camera = new PerspectiveCamera();
    camera.setRotationAxis(Rotate.X_AXIS);
    camera.setRotate(10);
    camera.setTranslateZ(200);
    scene.setCamera(camera);

    stage.setScene(scene);
    stage.show();
}

private Group createRotatingShapes() {
    final Box box1 = new Box(50, 50, 50);
    // Transparency in box1: last node of the group
    box1.setMaterial(new PhongMaterial(Color.web("#0000FF80")));

    box1.setTranslateZ(50);

    final Box box2 = new Box(10, 10, 10);
    box2.setMaterial(new PhongMaterial(Color.RED));

    box2.setTranslateZ(-50);

    shapes.getChildren().addAll(box2, box1);

    shapes.setTranslateX(200);
    shapes.setTranslateY(150);

    rotateAroundYAxis(box2);

    return shapes;
}

private int count = 0;
private void rotateAroundYAxis(Node node) {
    Rotate r = new Rotate(0, 0, 0, 100, Rotate.Y_AXIS);
    node.getTransforms().add(r);
    lastTimerCall = System.nanoTime();
    timeline = new AnimationTimer() {
        @Override public void handle(long now) {
            if (now > lastTimerCall + 100_000_000l) {
                r.setAngle((count++)%360);
            }
        }
    };
    timeline.start();
}


@Override
public void stop() {
    timeline.stop();
}

在盒子前面:

In front of

在蓝色盒子后面:

Behind

编辑

如果您查看相机的JavaDoc文档中的nearClip

在眼坐标空间中,指定此相机的近剪裁面距离眼睛的距离。 比nearClip更接近眼睛的物体不会被绘制。 nearClip被指定为大于零的值。小于或等于零的值将被视为非常小的正数。

(粗体是我的)。

所以,您代码的问题在于这一行:

camera.setNearClip(0);

只需将其更改为:

camera.setNearClip(0.01);

并且它将按照您的期望工作。


感谢您的快速回复,我确实看到您的解决方案运行良好,并且我愿意接受它作为答案。然而,我无法理解为什么在我的程序中,尽管cube1被放置在cube2后面,但它仍然在cube2之前渲染。能否请您解释一下“您如何定义一个盒子相对于另一个盒子的旋转”。非常感谢! - el_chupacabra
1
“Rotate r” 使用“pivotZ = 100”,即两个盒子之间的距离,所以您只需要旋转红色盒子。有了深度缓冲区,组中盒子的顺序并不重要,除了在蓝色盒子中设置透明度。如果您更改顺序,它也可以工作,但是蓝色盒子将不会透明。 - José Pereda
1
检查您的相机设置并更改此内容:camera.setNearClip(0.01);。现在您的代码将正常工作。我已经编辑了我的答案,加入了这个建议。 - José Pereda
2
错误的裁剪设置是微妙的。我也在另一个答案中遇到了这个问题,在那里我调试了一段时间并提出了一个解决方案,但最终注意到询问者只是设置了错误的裁剪平面。(在未来关于“JavaFX中奇怪的渲染问题”的问题中,我将首先检查裁剪平面...)。顺便加1。 - Marco13
谢谢,现在一切都好了。所有东西都被渲染成了预期的样子。我没有意识到将相机的 nearClip 设置为 0 可能会导致问题。文档中说:“小于或等于零的值被视为非常小的正数。”,所以我认为是安全的:S - el_chupacabra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接