Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overlaping Shapes - wrong overlapping shapes behaviour

Tags:

java

javafx

In short - I have 2 rotating rectangles. While rotating (by Y axis) they should overlap one over another - unfortunetlny one of ractangles is "always in front" despite of 180 degree turn. How to fix that behaviour? It looks like it is relevant to order in whitch rectangles hass been added to group. The one that was added as last is always in front.

scene:

    package drawing.scene;

import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Camera;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import drawing.objects.Clock;
import drawing.objects.Cube;

public class MyScene extends Application {

    private int sceneEdgeSize = 800;
    private int clolcSize = 400;

    @Override
    public void start(Stage primaryStage) throws Exception {
        Group g = new Group();
        g.setTranslateX((sceneEdgeSize - clolcSize) / 2f);
        g.setTranslateY((sceneEdgeSize - clolcSize) / 2f);

        final Cube c = new Cube(clolcSize);
        g.getChildren().add(c);
        Thread t = new Thread(new Runnable() {

            @Override
            public void run() {
                Rotate r = rotate(0, Rotate.Y_AXIS);
                c.getTransforms().add(r);
                double angle = 0.0;
                while (true) {

                    r.setAngle(angle += 2);
                    try {
                        Thread.sleep(25);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        });
        t.setDaemon(true);
        primaryStage.setScene(new Scene(g, sceneEdgeSize, sceneEdgeSize));
        PerspectiveCamera camera = new PerspectiveCamera();
        primaryStage.getScene().setCamera(camera);
        primaryStage.show();
        t.start();

    }

    public static void main(String[] args) {
        launch(args);
    }

    public Rotate rotate(double angle, Point3D axis) {
        return new Rotate(angle, clolcSize / 2f, clolcSize / 2f, 0, axis);
    }

}

cube class:

package drawing.objects;

import javafx.collections.ObservableList;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.RectangleBuilder;
import javafx.scene.transform.Rotate;

public class Cube extends Group {

    private double edgeLength = 0;

    public Cube(double edgeLength) {
        super();
        this.edgeLength = edgeLength;
        create();
    }

    private void create() {
        final Rotate rx = new Rotate(0, Rotate.X_AXIS);
        final Rotate ry = new Rotate(0, Rotate.Y_AXIS);
        final Rotate rz = new Rotate(0, Rotate.Z_AXIS);

        this.getTransforms().addAll(rx, ry, rz);

        ObservableList<Node> children = this.getChildren();
        //@formatter:off

        Rectangle rect;

        rect = RectangleBuilder // face
                .create()
                .width(edgeLength-20)
                .height(edgeLength-20)
                .translateZ(edgeLength * 0.5)
//                  .translateY(edgeLength * 0.5)
                //  .translateX(-edgeLength * 0.5)
                .fill(Color.LIGHTGREEN)
                .build()
                ;
        children.add(rect);
        rect = RectangleBuilder // face
                .create()
                .width(edgeLength-20)
                .height(edgeLength-20)
                .translateZ(-edgeLength * 0.5)
//              .translateY(-edgeLength * 0.5)
            //  .translateX(-edgeLength * 0.5)
                .fill(Color.DARKGREEN)
                .build()
                ;
        children.add(rect);


        //@formatter:on
    }
}
like image 442
Antoniossss Avatar asked Dec 12 '22 10:12

Antoniossss


1 Answers

You should switch depth buffering on in your scene.

The code in this question is largely obsolete and is also incorrect in parts:

  1. For JavaFX 3D work, it is recommended to use Java 8.
  2. For building a cube, use a Box shape.
  3. For other geometry types, use a Sphere, Cylinder or MeshView.
  4. Use Point and Ambient lights to illuminate your Scene.
  5. Apply Materials to your 3D objects to shade them.
  6. Use Model importers to import complex mesh models.
  7. Builders are deprecated.
  8. For handling animation it is not recommended to spawn another thread, but to use the JavaFX animation package.
  9. For the particular animation in your question, a RotateTransition is the appropriate animation.
  10. Your solution is not threadsafe. You should not modify properties of nodes in the active scene graph (e.g. the transform properties of a displayed node) off of the application thread (use Platform.runLater instead).
  11. You are not creating a scene with depth buffering set to true. The depth buffering flag tells JavaFX that it should apply depth sorting and culling to 3D objects.

Also check that your system supports JavaFX 3D:

System.out.println(
  "3D supported? " + 
  Platform.isSupported(ConditionalFeature.SCENE3D)
);

Java 8 3D sample code for a rotating cube

Here is a rotating cube coded in Java 8.

rotatingcube

import javafx.animation.*;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.paint.*;
import javafx.scene.shape.Box;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;

public class RotatingCube extends Application {

    private static final double SCENE_SIZE = 300;
    private static final double BOX_EDGE_LENGTH = SCENE_SIZE / 2d;

    private static final Color BOX_COLOR     = Color.DARKGREEN;
    private static final Color AMBIENT_COLOR = Color.rgb(30, 30, 30);
    private static final Color LIGHT_COLOR   = Color.WHITE;

    private static final Duration ROTATION_DURATION = Duration.seconds(4.5);

    @Override
    public void start(Stage stage) throws Exception {
        Scene scene = new Scene(
                new Group(
                        new AmbientLight(AMBIENT_COLOR),
                        createPointLight(),
                        createRotatingBox()
                ),
                SCENE_SIZE, SCENE_SIZE,
                true,
                SceneAntialiasing.BALANCED
        );
        scene.setFill(Color.MIDNIGHTBLUE.darker().darker().darker());
        scene.setCamera(new PerspectiveCamera());

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

    private PointLight createPointLight() {
        PointLight light = new PointLight(LIGHT_COLOR);
        light.setTranslateX( SCENE_SIZE / 2d);
        light.setTranslateY( SCENE_SIZE / 2d);
        light.setTranslateZ(-SCENE_SIZE);

        return light;
    }

    private Box createRotatingBox() {
        final Box box = new Box(BOX_EDGE_LENGTH, BOX_EDGE_LENGTH, BOX_EDGE_LENGTH);
        box.setTranslateX(SCENE_SIZE / 2d);
        box.setTranslateY(SCENE_SIZE / 2d);
        box.setTranslateZ(BOX_EDGE_LENGTH / 2d);
        box.setMaterial(new PhongMaterial(BOX_COLOR));

        rotateAroundYAxis(box);

        return box;
    }

    private void rotateAroundYAxis(Box box) {
        RotateTransition rotate = new RotateTransition(ROTATION_DURATION, box);
        rotate.setFromAngle(0);
        rotate.setToAngle(360);
        rotate.setAxis(Rotate.Y_AXIS);
        rotate.setCycleCount(RotateTransition.INDEFINITE);
        rotate.setInterpolator(Interpolator.LINEAR);
        rotate.play();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

Java 8 3D sample code for two rotating rectangles

import javafx.animation.*;
import javafx.application.*;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;

public class RotatingRectangles extends Application {

    private static final double SCENE_SIZE = 300;
    private static final double EDGE_LENGTH = SCENE_SIZE / 2d;

    private static final Duration ROTATION_DURATION = Duration.seconds(4.5);

    @Override
    public void start(Stage stage) throws Exception {
        System.out.println(
            "3D supported? " +
            Platform.isSupported(ConditionalFeature.SCENE3D)
        );

        Scene scene = new Scene(
                createRotatingShapes(),
                SCENE_SIZE, SCENE_SIZE,
                true,
                SceneAntialiasing.BALANCED
        );
        scene.setFill(Color.MIDNIGHTBLUE.darker().darker().darker());
        scene.setCamera(new PerspectiveCamera());

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

    private Group createRotatingShapes() {
        final Rectangle rect1 = new Rectangle(
            EDGE_LENGTH, EDGE_LENGTH,
            Color.LIGHTGREEN
        );
        rect1.setTranslateX(-EDGE_LENGTH / 2d);
        rect1.setTranslateY(-EDGE_LENGTH / 2d);
        rect1.setTranslateZ( EDGE_LENGTH / 2d);

        final Rectangle rect2 = new Rectangle(
            EDGE_LENGTH, EDGE_LENGTH,
            Color.DARKGREEN
        );
        rect2.setTranslateX(-EDGE_LENGTH / 2d);
        rect2.setTranslateY(-EDGE_LENGTH / 2d);
        rect2.setTranslateZ(-EDGE_LENGTH / 2d);

        final Group shapes = new Group(
            rect1, rect2
        );

        shapes.setTranslateX(SCENE_SIZE / 2d);
        shapes.setTranslateY(SCENE_SIZE / 2d);
        shapes.setTranslateZ(EDGE_LENGTH / 2d);

        rotateAroundYAxis(shapes);

        return shapes;
    }

    private void rotateAroundYAxis(Node node) {
        RotateTransition rotate = new RotateTransition(ROTATION_DURATION, node);
        rotate.setFromAngle(0);
        rotate.setToAngle(360);
        rotate.setAxis(Rotate.Y_AXIS);
        rotate.setCycleCount(RotateTransition.INDEFINITE);
        rotate.setInterpolator(Interpolator.LINEAR);
        rotate.play();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

In the first picture the dark rectangle has been rotated in front of the light rectangle.

In the first picture the light rectangle has been rotated in front of the dark rectangle.

So you can see that the JavaFX system is correctly displaying the depth sorted shapes in the scene.

rotatingrectdarkrotatingrectlight

like image 56
jewelsea Avatar answered Dec 22 '22 04:12

jewelsea