ドキュメント



JavaFX: JavaFXグラフィックスの操作

3 カメラ

この章では、JavaFX 3Dグラフィックス機能に含まれるCamera APIについて説明します。

カメラは、JavaFX Sceneグラフに追加できるノードとなったため、3D UIレイアウト内で移動できるようになりました。この点は、カメラが1つの位置にとどまっていた2Dレイアウトとは異なります。

JavaFXシーン座標空間では、デフォルトのカメラの投影面はZ=0に配置され、カメラの座標系は次のとおりです。

• X軸は右方向を指します。

• Y軸は下方向を指します。

• Z軸は見る人から反対側の、画面の奥方向を指します。

透視投影カメラ

JavaFXでは、3Dシーンをレンダリングするために透視投影カメラが提供されます。このカメラによって、透視投影の視野空間が定義されます。視野空間は、fieldOfViewプロパティの値を変更することによって変更できます。

例3-1は、透視投影カメラを作成するための2つのコンストラクタを示しています。

例3-1 PerspectiveCameraのコンストラクタ

PerspectiveCamera()

PerspectiveCamera(boolean fixedEyeAtCameraZero)

後のコンストラクタはJavaFX 8の新しいコンストラクタであり、3D環境でカメラが捉えたものをレンダリングするように、fixedEyeAtCameraZeroフラグを指定してカメラ位置を制御できます。

3Dグラフィックスのプログラミングには、次のコンストラクタを使用する必要があります。

PerspectiveCamera(true);

オプションfixedEyeAtCameraZerotrueに設定すると、投影領域の寸法の変更やウィンドウのサイズ変更にかかわらず、PerspectiveCameraは、眼の位置をその座標空間の(0, 0, 0)に固定して構築されます。

fixedEyeAtCameraZeroをデフォルト値のfalseに設定すると、カメラによって定義される座標系の原点は、パネルの左上隅になります。このモードは、透視投影カメラでレンダリングされる2D UIコントロールに使用されますが、ほとんどの3Dグラフィックス・アプリケーションには有用ではありません。たとえば、ウィンドウのサイズが変更されると、パネルの左上隅にある原点を保持するためにカメラは移動します。これは2D UIレイアウトの場合に必要ですが、3Dレイアウトでは望ましくありません。そのため、3Dグラフィックスを実行してカメラを変換または移動するときは、fixedEyeAtCameraZeroプロパティを必ずtrueに設定することが重要です。

カメラを作成してシーンに追加するには、次のコード行を使用します。

Camera camera = new PerspectiveCamera(true);
     scene.setCamera(camera);

次のコードを使用して、カメラをシーン・グラフに追加します。

Group cameraGroup = new Group();
     cameraGroup.getChildren().add(camera);
     root.getChildren().add(cameraGroup);

カメラを回転させてcameraGroupを移動するには、次のコード行を使用します。

camera.rotate(45);
     cameraGroup.setTranslateZ(-75);

視野

カメラの視野は、次のように設定できます。

camera.setFieldOfView(double value);

視野が大きくなるほど、透視図のゆがみやサイズの差異が増します。

  • Fisheyeレンズは180度またはそれ以上の最大視野を持ちます。

  • Normalレンズは40度から62度の視野を持ちます。

  • Telephotoレンズは1度(未満)から30度の視野を持ちます。

クリップ面

ローカル座標系でのカメラの近クリップ面を次のように設定できます。

camera.setNearClip(double value);

ローカル座標系でのカメラの遠クリップ面を設定するには、次を使用します。

camera.setFarClip(double value);

近クリップ面または遠クリップ面を設定すると、視野空間が決まります。近クリップ面が大きすぎる場合、基本的にはシーンの前方のクリッピングが開始されます。小さすぎる場合は、シーンの背後のクリッピングが開始されます。

ヒント:

不適切なビジュアル・アーティファクトが表れ始める場合があるため、近クリップ値を必要以上に小さい値に設定したり、遠クリップ値を必要以上に大きい値に設定しないでください。

クリップ面は、シーンの十分な部分が表示されるように設定する必要があります。しかし、表示範囲は数値エラーが発生するほど大きい値に設定しないでください。近クリップ面の値が大きすぎると、シーンのクリップが始まります。しかし、近クリップ面が小さすぎると、値がゼロに近すぎることにより、異なる種類のビジュアル・アーティファクトが表示されます。遠クリップ面の値が大きすぎる場合も、特に近クリップ面の値が小さすぎる場合に、数値エラーが発生します。

Y-downとY-up

ほとんどの2Dグラフィックス座標系(UIを含む)では、画面を下方向に進むとYが大きくなります。これは、PhotoShop、JavaFXおよびIllustratorに当てはまります。基本的に、ほとんどの2Dパッケージはこのように機能します。多くの3Dグラフィックス座標系では、通常、画面を上方向に移動するとYが大きくなります。一部の3Dグラフィックス座標系では上方向に移動するとZが大きくなりますが、ほとんどは画面を上方向に移動するとYが大きくなります。

Y-downとY-upは、どちらもそれらの固有のコンテキストでは適切です。JavaFXでは、カメラの座標系はY-downであり、これは、X軸は右方向を指し、Y軸は下方向を指し、Z軸は見る人から反対側の画面の奥方向を指すことを意味します。

Y-upとしての3Dシーンを検討する場合、例3-2に示すように、root3DというXformノードをルートの下に作成できます。そのrx.setAngleプロパティを180度に設定して、基本的に上下逆にします。次に、3D要素をroot3Dノードに追加し、カメラをroot3Dの下に置きます。

例3-2 Xformノード(root3D)の作成

root3D = new Xform();
root3D.rx.setAngle(180.0);
root.getChildren().add(root3D);
root3D.getChildren().add(...); // add all your 3D nodes here

例3-3に示すように、cameraXformというXformノードを作成し、ルートの下に置くこともできます。それを上下逆にして、カメラをcameraXformの下に置きます。

例3-3 cameraXformノードの作成

Camera camera = new PerspectiveCamera(true);
Xform cameraXform = new Xform();
root.getChildren().add(cameraXform);
cameraXform.getChildren().add(camera);
cameraXform.rz.setAngle(180.0);

カメラ・ノード上でのわずかな違いがありますが、さらによい方法は、カメラに180度回転を追加することです。自動ピボットを避けるため、自動的に提供される回転は使用しません。例3-4では、カメラは180度回転され、cameraXformの子としてカメラに追加されます。わずかな違いとは、cameraXformは初期の値を保持し、そのデフォルトの位置を保ち、平行移動や回転を含め、すべてのものがゼロになることです。

例3-4 cameraXformの作成および回転

Camera camera = new PerspectiveCamera(true);
Xform cameraXform = new Xform();
root.getChildren().add(cameraXform);
cameraXform.getChildren().add(camera);
Rotate rz = new Rotate(180.0, Rotate.Z_AXIS);
camera.getTransforms().add(rz);

PerspectiveCameraを使用するサンプル・コード

例3-5に示すSimple3DBoxAppのサンプルでは、3Dボックスが作成され、シーンのレンダリングに透視投影カメラが使用されます。このサンプル・アプリケーションは、http://www.oracle.com/technetwork/java/javase/downloads/で「JavaFX Demos and Samples」セクションからダウンロードできるEnsemble 8サンプルの一部です。

MSAAApp.javaアプリケーションでも、Camera APIの使用方法の例が提供されます。

例3-5 3Dボックスのサンプル・アプリケーション

package simple3dbox;
 
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SubScene;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.DrawMode;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
 
public class Simple3DBoxApp extends Application {
 
    public Parent createContent() throws Exception {
 
        // Box
        Box testBox = new Box(5, 5, 5);
        testBox.setMaterial(new PhongMaterial(Color.RED));
        testBox.setDrawMode(DrawMode.LINE);
 
        // Create and position camera
        PerspectiveCamera camera = new PerspectiveCamera(true);
        camera.getTransforms().addAll (
                new Rotate(-20, Rotate.Y_AXIS),
                new Rotate(-20, Rotate.X_AXIS),
                new Translate(0, 0, -15));
 
        // Build the Scene Graph
        Group root = new Group();       
        root.getChildren().add(camera);
        root.getChildren().add(testBox);
 
        // Use a SubScene       
        SubScene subScene = new SubScene(root, 300,300);
        subScene.setFill(Color.ALICEBLUE);
        subScene.setCamera(camera);
        Group group = new Group();
        group.getChildren().add(subScene);
        return group;
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setResizable(false);
        Scene scene = new Scene(createContent());
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * Java main for when running without JavaFX launcher
     */
    public static void main(String[] args) {
        launch(args);
    }
}
ウィンドウを閉じる

目次

JavaFX: JavaFXグラフィックスの操作

展開 | 縮小