Javaに関する様々な情報をご紹介します。

Javaに関する様々な情報をご紹介します。
評価

0

[JavaFX 3D]見えないはずの物が見える

Java初めて1年くらいの初心者です。
JavaFX 3Dの存在を知って少し実験的にやってみたのですが、見えないはずの物が見えてるのですが、、、これは仕様、コードのミス、ハードのせい、どれでしょうか。
具体的には下記のコードでtestBoxの後ろにあるはずのspが見えます。
rootに入れる順番が後の物が、前の物の上に描画されているように思えます(矢印のキー等でカメラを色々な場所に動かしてみても常にspがtestBoxの上に描画されています)。

ご回答よろしくお願い致しますm(._.)m

以下全てコード
---------------------------------------------------------------------------------------
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.EventHandler;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SubScene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.Sphere;
import javafx.scene.text.Font;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;

public class Hello extends Application {

    private PerspectiveCamera camera;
    private Translate cameraTranslate = new Translate(0, 0, -1000);
    private Point3D cameraPivot = new Point3D(0, 0, 0);
    private Rotate cameraRotateX = new Rotate(0, Rotate.X_AXIS);
    private Rotate cameraRotateY = new Rotate(0, Rotate.Y_AXIS);
    private Rotate cameraRotateZ = new Rotate(0, Rotate.Z_AXIS);
    private Group root = new Group();
    private GraphicsContext gc;
    private double screenWidth=600;
    private double screenHeight=600;


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

    }

    private Parent createContent() {
        Box testBox = new Box(100, 100, 100);
        PhongMaterial boxMaterial = new PhongMaterial(Color.GREEN);
        boxMaterial.setSpecularColor(Color.LIGHTGREEN);
        
        testBox.setMaterial(boxMaterial);
        testBox.setDrawMode(DrawMode.FILL);

        Sphere sp = new Sphere(10);
        sp.setMaterial(new PhongMaterial(Color.BLUE));
        sp.setDrawMode(DrawMode.FILL);
        sp.setTranslateZ(100);
        
        camera = new PerspectiveCamera(true);
        camera.getTransforms().addAll(cameraTranslate, cameraRotateX, cameraRotateY, cameraRotateZ);
        camera.setFarClip(1_000_000);

        root.getChildren().addAll(testBox, sp, camera);

        SubScene subScene = new SubScene(root, screenWidth, screenHeight);
        subScene.setFill(Color.BLACK);
        subScene.setCamera(camera);

        return new Group(subScene);
    }

    @Override
    public void start(Stage stage) throws Exception {
        StackPane stackPane = new StackPane(createContent());
        Canvas canvas = new Canvas(screenWidth, screenHeight);
        gc = canvas.getGraphicsContext2D();
        stackPane.getChildren().add(canvas);
        Scene scene = new Scene(stackPane);

        scene.setOnKeyPressed(getMainKeyPressEvent());

        stage.setScene(scene);
        stage.setTitle("JavaFX3D");
        stage.show();

    }

    private EventHandler<KeyEvent> getMainKeyPressEvent() {
        EventHandler<KeyEvent> e = (KeyEvent event) -> {
            //System.out.println(event.getCode().toString());
            Point3D p;

            switch (event.getCode()) {
                case RIGHT:
                    cameraRotateY.setAngle(cameraRotateY.getAngle() + 5);
                    break;
                case LEFT:
                    cameraRotateY.setAngle(cameraRotateY.getAngle() - 5);
                    break;
                case UP:
                    cameraRotateX.setAngle(cameraRotateX.getAngle() + 5);
                    break;
                case DOWN:
                    cameraRotateX.setAngle(cameraRotateX.getAngle() - 5);
                    break;
                case SLASH:
                    cameraRotateZ.setAngle(cameraRotateZ.getAngle()-5);
                    break;
                case BACK_SLASH:
                    cameraRotateZ.setAngle(cameraRotateZ.getAngle()+5);
                    break;
                case PAGE_UP:
                    p = new Point3D(0, 0, 10);
                    p = cameraTranslate.transform(p);
                    cameraTranslate.setX(p.getX());
                    cameraTranslate.setY(p.getY());
                    cameraTranslate.setZ(p.getZ());
                    break;
                case PAGE_DOWN:
                    p = new Point3D(0, 0, -10);
                    p = cameraTranslate.transform(p);
                    cameraTranslate.setX(p.getX());
                    cameraTranslate.setY(p.getY());
                    cameraTranslate.setZ(p.getZ());
                    break;
                case D:
                    p = new Point3D(10, 0, 0);
                    cameraPivot = cameraPivot.add(p);
                    p = cameraTranslate.transform(p);
                    cameraTranslate.setX(p.getX());
                    cameraTranslate.setY(p.getY());
                    cameraTranslate.setZ(p.getZ());
                    break;
                case A:
                    p = new Point3D(-10, 0, 0);
                    cameraPivot = cameraPivot.add(p);
                    p = cameraTranslate.transform(p);
                    cameraTranslate.setX(p.getX());
                    cameraTranslate.setY(p.getY());
                    cameraTranslate.setZ(p.getZ());
                    break;
            }
            
            if(cameraRotateX.getAngle()>=360)
                cameraRotateX.setAngle(cameraRotateX.getAngle()-360);
            else if(cameraRotateX.getAngle()<0)
                cameraRotateX.setAngle(cameraRotateX.getAngle()+360);
            if(cameraRotateY.getAngle()>=360)
                cameraRotateY.setAngle(cameraRotateY.getAngle()-360);
            else if(cameraRotateY.getAngle()<0)
                cameraRotateY.setAngle(cameraRotateY.getAngle()+360);
            if(cameraRotateZ.getAngle()>=360)
                cameraRotateZ.setAngle(cameraRotateZ.getAngle()-360);
            else if(cameraRotateZ.getAngle()<0)
                cameraRotateZ.setAngle(cameraRotateZ.getAngle()+360);
            
            p = cameraPivot.subtract(cameraTranslate.getX(), cameraTranslate.getY(), cameraTranslate.getZ());
            cameraRotateX.setPivotX(p.getX());
            cameraRotateX.setPivotY(p.getY());
            cameraRotateX.setPivotZ(p.getZ());
            cameraRotateY.setPivotX(p.getX());
            cameraRotateY.setPivotY(p.getY());
            cameraRotateY.setPivotZ(p.getZ());
            cameraRotateZ.setPivotX(p.getX());
            cameraRotateZ.setPivotY(p.getY());
            cameraRotateZ.setPivotZ(p.getZ());

            gc.setFill(Color.WHITE);
            gc.setFont(Font.font(16));
            gc.clearRect(0, 0, gc.getCanvas().getWidth(), gc.getCanvas().getHeight());
            gc.fillText("Camera Pivot\t[" + cameraPivot.getX() + ", " + cameraPivot.getY() + ", " + cameraPivot.getZ() + "]\n"+
                    "Camera Rotate\t[X="+cameraRotateX.getAngle()+", Y="+cameraRotateY.getAngle()+", Z="+cameraRotateZ.getAngle()+"]", 10, 20);
        };
        return e;
    }
}

2

回答

640

閲覧

2件の回答

評価

0

Sceneにdepth bufferを使う指定をしてないのが原因と思います。
depth bufferがないと複数の図形の陰面処理は行われず、質問者さんがおっしゃるとおり単純にコンテナ上の兄弟の順番に画面に描画されてしまうようです。

JavaFXは常に3Dのメカニズムで描画されており3D的(透視射影)になるかどうかはカメラの指定次第ということのようです。常に3Dで描画するとはいえ2D的(平行射影)な描画が主な用途になることから、平行射影では不要(そして多分コストがかかる)depth bufferは明示的に指定しない限り無効という仕様にしたのだと思います。

評価

0

失礼、「2D的(平行射影)」だとdepth bufferがいらないというのはおかしな説明でした。

描画対象の描画順序が以下のようにコンポーネント階層だけで決まる描画モデルではdepth bufferが不要というべきでした。
1. コンポーネント階層上位から下位
2. コンテナ配下ではコンテナに追加された順番

「2D的な描画ならdepth bufferはいらない」とだけいえばよかったんですが、「2D的(平行射影)」と余計な単語を補ったため誤解をまねく表現になってしまいました。

質問から6ヶ月以上経過しているので、回答を書き込むことはできません。