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:)
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:
Behind the blue box:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With