Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX 8 Z-buffer issue

My problem is with Z-Buffer in JavaFX 3D, it does not seem to work as intended on my machine.

I'am aware of questions: Overlapping shapes and ...Z Order...

However I do have Z-Buffer enabled, and nodes are still being rendered in the order they are added to the scenegraph.

Maybe I'm missing some dependencies or whatsoever?

I'm posting the code, I hope someone can help me. I'm creating a transition that moves the node around another on an elliptic path.

Thank you in advance!

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;
}

}

This was my first post by the way:)

like image 338
el_chupacabra Avatar asked Feb 06 '16 10:02

el_chupacabra


1 Answers

If you check the code on the link you provided using rectangles, depth buffer works fine.

Changing the rectangles to use 3D boxes works as well.

The issue is how you define the rotation of one of the boxes related to the other, so instead of using a RotateTransition or a SequentialTransition of TranslateTransition like you do, I've applied a Rotate transform to the red box setting a pivot in the center of the blue one, and used an AnimationTimer to modify the angle of that rotation to create the 'orbit' effect.

You can even use transparency on the big box (since 8u60) to see the small one beneath it.

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 the box:

In front of

Behind the blue box:

Behind

EDIT

If you have a look to the Camera JavaDoc for nearClip:

Specifies the distance from the eye of the near clipping plane of this Camera in the eye coordinate space. Objects closer to the eye than nearClip are not drawn. nearClip is specified as a value greater than zero. A value less than or equal to zero is treated as a very small positive number.

(bold is mine).

So the problem with your code was this line:

camera.setNearClip(0);

Just change it to:

camera.setNearClip(0.01);

and it will work as you expected.

like image 165
José Pereda Avatar answered Nov 13 '22 03:11

José Pereda