JavaOne 2013 SFで、いくつかJavaFX 3Dのセッションを聴講したので、簡単な3D表示プログラムを動かしてみたくなりました。自宅・職場のPCでプログラミングして実行したところ、PCの環境によって動いたもの、動かないものがありました。
試してみた環境
ノートPC(1)
2,3年前のモデルで、CPUはIntel Core i7 640M(Nehalemアーキテクチャ)、グラフィックスはCPU内蔵のIntel HD Graphics、OSはWindows 7 32bit、です。
このPCでは、JavaFX 3Dプログラムは実行可能なものの3Dシェープが表示されません。JVM起動オプションに-Dprism.verbose=trueを指定してログを見ると、
- Direct3D初期化に失敗
- ドライバのバージョンが古いので8.15.10.2302以上にアップデートせよ
- Prismソフトウェアパイプラインにフォールバック
- ConditionalFeature.SCENE3Dをサポートせず
といった内容のメッセージが出ています。
次がログの主要部分(抜粋)です。
Prism pipeline init order: d3d sw Using platform text rasterizer Using native-based Pisces rasterizer Using dirty region optimizations Not using texture mask for primitives Not forcing power of 2 sizes for textures Using hardware CLAMP_TO_ZERO mode Opting in for HiDPI pixel scaling Prism pipeline name = com.sun.prism.d3d.D3DPipeline Loading D3D native library ... succeeded. D3DPipelineManager: Created D3D9 device Direct3D initialization failed Adapter validation failed for all adapters Device "Intel(R) HD Graphics" (\\.\DISPLAY1) initialization failed : WARNING: bad driver version detected, device disabled. Please update your driver to at least version 8.15.10.2302 (X) Got class = class com.sun.prism.d3d.D3DPipeline GraphicsPipeline.createPipeline: error initializing pipeline com.sun.prism.d3d.D3DPipeline *** Fallback to Prism SW pipeline Prism pipeline name = com.sun.prism.sw.SWPipeline (X) Got class = class com.sun.prism.sw.SWPipeline Initialized prism pipeline: com.sun.prism.sw.SWPipeline vsync: true vpipe: false 10 12, 2013 3:07:48 午後 javafx.scene.PerspectiveCamera <init> WARNING: System can't support ConditionalFeature.SCENE3D 10 12, 2013 3:07:48 午後 javafx.scene.paint.Material <init> WARNING: System can't support ConditionalFeature.SCENE3D 10 12, 2013 3:07:48 午後 javafx.scene.paint.Material <init> WARNING: System can't support ConditionalFeature.SCENE3D 10 12, 2013 3:07:48 午後 javafx.scene.shape.Shape3D <init> WARNING: System can't support ConditionalFeature.SCENE3D 10 12, 2013 3:07:48 午後 javafx.scene.LightBase <init> WARNING: System can't support ConditionalFeature.SCENE3D 10 12, 2013 3:07:48 午後 javafx.scene.Scene <init> WARNING: System can't support ConditionalFeature.SCENE3D 10 12, 2013 3:07:48 午後 javafx.scene.Scene$7 invalidated WARNING: System can't support ConditionalFeature.SCENE3D 10 12, 2013 3:07:49 午後 javafx.scene.shape.Mesh <init> WARNING: System can't support ConditionalFeature.SCENE3D QuantumRenderer: shutdown
Intelのサイトを見ると、次のドライバダウンロードページから最新ドライバ(15.22.58.2993)がダウンロード可能となっていました。
これを入れることができれば動作するかもしれませんが、PCメーカーがカスタマイズしたドライバが入っているので、更新できないとエラーになってしまいました。
メーカーはドライバの更新をしてないので、難しいです。
(追記)いったんディスプレイドライバーを削除します。すると、再起動がかかってVGA(640x480)の低解像度となるので、そこでIntelから入手したドライバーをインストールします。これでJavaFX 3Dがうごくようになりました。
ノートPC(2)
8年前のモデルで、CPUはPentium M 750(Dothanアーキテクチャ)、グラフィックスは GeForce GO 6200 with TC、OSはWindows XP 32bitです。
このPCでは、jdk 8 b109をインストールするときに警告(Windowsの新しいバージョンしかサポートしませんよ)が表示されますが、インストールは続行できます。JavaFX 3Dのプログラムを実行して画面表示されました。
グラフィックスドライバの更新も不要でした。
JavaFX 3Dの単純なプログラム
JavaFX 3DのいわゆるHello World的なプログラムを探してみました。見つかったのは次ですが、やはりちょっと複雑です。
球と立方体を表示するサンプルです。
JavaFX公式ドキュメントの一つです。ちょっと複雑なサンプルです。
そこで、球体を1つだけ表示する超入門サンプル作りにチャレンジしました(これが難物でした・・・)。
最初の取り組み、真っ白な表示
まず、空っぽのシーングラフを表示するJavaFXアプリケーションのスケルトンを記述します。
import javafx.application.Application; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.Group; public class Hello extends Application { @Override public void start(Stage stage) { Group root = new Group(); Scene scene = new Scene(root, 640, 480); stage.setTitle("Hello JavaFX 3D World!"); stage.setScene(scene); stage.show(); } public static void main(String... args) { launch(args); } }
次に、3次元の球体を表現するシェープSphereをシーングラフに追加します。
--- Hello.java.1 2013-10-12 22:22:57.900452400 +0900 +++ Hello.java 2013-10-12 22:30:07.583576200 +0900 @@ -2,12 +2,15 @@ import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.Group; +import javafx.scene.shape.Sphere; public class Hello extends Application { @Override public void start(Stage stage) { Group root = new Group(); + Sphere Sphere = new Sphere(200); + root.getChildren().add(Sphere); Scene scene = new Scene(root, 640, 480); stage.setTitle("Hello JavaFX 3D World!"); stage.setScene(scene);
これを実行すると先ほどの中身が真っ白のウィンドウが表示されるだけでした。
JavaFX 3Dには、カメラという概念があり、3次元上の物体をパースペクティブ表示する際の視線の位置や方向を指定します。この視線が定まって始めて3次元上の物体が2次元である画面に描画されます。カメラの定義がないと、3次元空間の物体が2次元の画面に描画できないので、カメラの定義を追加します。
--- Hello.java.2 2013-10-12 22:35:38.448159400 +0900 +++ Hello.java 2013-10-12 22:55:46.012454400 +0900 @@ -3,6 +3,8 @@ import javafx.scene.Scene; import javafx.scene.Group; import javafx.scene.shape.Sphere; +import javafx.scene.Camera; +import javafx.scene.PerspectiveCamera; public class Hello extends Application { @@ -12,6 +14,8 @@ Sphere Sphere = new Sphere(100); root.getChildren().add(Sphere); Scene scene = new Scene(root, 320, 320); + Camera camera = new PerspectiveCamera(); + scene.setCamera(camera); stage.setTitle("Hello JavaFX 3D World!"); stage.setScene(scene); stage.show();
すると、なにやら球体っぽい表示が出ました。
まず、デフォルトのカメラ(PerspetiveCamera)はコンストラクタの引数なしの場合、画面左上隅を原点(0, 0, 0)とした座標系(2Dと同じ)となります。
シーンに球体を半径100で作成したので、位置は球体中心が(0, 0, 0)となります。そのため、このような表示になります。
なお、カメラには視野角(Field of View)、クリッピング面などいくつもパラメータがありますが、ここでは考えないことにします。
このあと、球体の材質、色、位置の指定や、光源の指定などをするのですが、その指定方法はまたいずれ・・・