Search code examples
javajavafx3dfxml

How to set SceneAntialiasing to SubScene created in FXML file?


I keep playing with 3D in JavaFX.

I added SubScene with some Box to my demo app but the edges of the Boxare nasty. How can I smooth them without using SceneAntialiasing.BALANCED in constructor? I've seen there is possibility to add antiAliasing="" in FXML file, but then I don't know what should be putted as the parameter. Word BALANCED is not working.

Controller.java

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.fxml.FXML;
import javafx.scene.*;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.util.Duration;


public class Controller{

    @FXML
    private SubScene subscene;
    @FXML
    private AnchorPane pane;
    private Box box= new Box();
    private PerspectiveCamera camera = new PerspectiveCamera(true);
    private Group group = new Group();


    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);
    private Timeline animation;



    @FXML
    void initialize() {

        box.setMaterial(new PhongMaterial(Color.ORANGE));
        box.setDepth(10);
        box.setWidth(10);
        box.setHeight(10);
        rx.setAngle(90);
        ry.setAngle(25);
        box.getTransforms().addAll(rz, ry, rx);


        group.getChildren().add(box);

        animation = new Timeline();
        animation.getKeyFrames().addAll(
                new KeyFrame(Duration.ZERO,

                        new KeyValue(box.depthProperty(), 0d),
                        new KeyValue(box.translateYProperty(),400d)),
                new KeyFrame(Duration.seconds(5),

                        new KeyValue(box.depthProperty(), 800d),
                        new KeyValue(box.translateYProperty(), 0d)));

        animation.setCycleCount(Timeline.INDEFINITE);


        camera.getTransforms().add(new Translate(0, 0, -80));
        camera.getTransforms().addAll (

                new Rotate(-35, Rotate.X_AXIS),
                new Translate(0, 0, 10)
        );

        subscene.setRoot(group);
        subscene.setCamera(camera);
        animation.play();
    }

}

main.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.SubScene?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.Region?>

<AnchorPane fx:id="pane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="check.brakes.Controller">
   <children>
      <SubScene fx:id="subscene" height="697.0" layoutX="78.0" layoutY="54.0" width="643.0" AnchorPane.bottomAnchor="49.0" AnchorPane.leftAnchor="78.0" AnchorPane.rightAnchor="79.0" AnchorPane.topAnchor="54.0" >
        <root>
          <Region />
        </root>
      </SubScene>
      <Button layoutX="196.0" layoutY="186.0" mnemonicParsing="false" text="Button" />
      <Button fx:id="btn2" layoutX="450.0" layoutY="186.0" mnemonicParsing="false" text="Button" />
      <Label layoutX="386.0" layoutY="36.0" text="test" />
      <Label layoutX="381.0" layoutY="753.0" text="test 2" />
   </children>
</AnchorPane>

Is there any other way to achieve that?


Solution

  • Since SceneAntialiasing is not an enum you can't use the constant name in an attribute. However, the SubScene constructor does annotate the SceneAntialiasing parameter with @NamedArg, which means it can be injected when created via FXML. You just need to use an element in combination with fx:constant instead of an attribute. For example:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.SubScene?>
    <?import javafx.scene.SceneAntialiasing?>
    
    <SubScene xmlns="http://javafx.com/javafx/12.0.1" xmlns:fx="http://javafx.com/fxml/1">
        <antiAliasing>
            <SceneAntialiasing fx:constant="BALANCED"/>
        </antiAliasing>
    </SubScene>
    

    Loading the above with:

    import java.io.IOException;
    import javafx.application.Application;
    import javafx.application.Platform;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.SubScene;
    import javafx.stage.Stage;
    
    public final class App extends Application {
    
        @Override
        public void start(Stage primaryStage) throws IOException {
            SubScene scene = FXMLLoader.load(getClass().getResource(...));
            System.out.println(scene.getAntiAliasing());
            Platform.exit();
        }
    
    }
    

    Resulted in BALANCED being printed.