Java3Dを触り始めたので、何か作ってみようと思って作り始めたのだが、想定したものが意外に難しいことがわかってきて、挫折気味である。しかし、その途中段階でできたテストアプリが、自己満足に浸れるくらいには興味深く動いたので、一旦区切りをつけて、公開することにする。
・何らかのアプレットのページへのリンク
・ソースコード
J3DTest2.java
TimerBehavior.java
TimerBehaviorProcess.java
Java3D(OpenGL)のイベントのスケジューラーはAWTやSwingのそれとは別であり、例えばAWTやSwingのパーツに対してrepaint()してもCanvas3Dは再描画されない。Java3Dのイベント処理モデルに合わせるには、Behavior(javax.media.j3d.Behavior)というクラスを継承するクラスでイベントを処理する必要がある。
Java3Dでアニメーションするには、その理由により、java.util.Timerやjavax.swing.Timerを使ってAWTやSwingで処理するだけではうまくいかず、Canvas3D、Bounds(BoundingBox,BoundingSphere etc.)に関連付けたBehaviorに処理を渡さないといけない。Java3Dのアニメーションをさせるだけなら、java.util.Timerやjavax.swing.Timerを使うよりBehaviorを使う方が賢明だと思われる。
とりあえず、javax.media.j3d.WakeupOnElapsedTimeのを使って周期的にBehaviorを動かせるようなので、今回のアプリでは、それを使ったTimerBehaviorというのを定義している。
一定の速度の移動や一定周期の回転や一定の拡大率の拡大など、変化量が一定なアニメーションなら、なんとかInterpolatorというBehaviorを使えばシンプルである。今回できたアプレットもInterpolatorを使うと美しく書けるのかも知れないが、拡張性を求めて敬遠した。
Interpolatorは便利でスマートだと言われるが、確かに簡単に動かしてみることはできるが、無造作に使うとクライアントのCPU時間をフルに使ったりするので、きちんと動かすには多くの設定項目を理解しないといけない。3Dするためには避けて通れないのかも知れないが、使いこなせるまでに覚えることが多そうで、そこそこ敷居が高い。
WakeupOnなんとかで、色々な条件でBehaviorを起動できるようである。WakeupOn*の種類がイベントの種類のような感じか。
Java3Dに限った話ではないが、SwingのJAppletのinit()でUIのパーツを作るには、invokeLater()を使うのは誤りで、invokeAndWait()を使わないといけないようだ。詳しいことはわからないが、今回、init()でinvokeLater()を使ってUIのパーツを作ると、何も表示されなかった。Swingのinitスレッドは早く終わらないといけないとなっている(ブラウザが困るかも知れない)ので、init()で時間がかかりそうなJava3Dのオブジェクトを生成するのはまずいと思う。JFrameへのコンポーネント追加はinvokeLater()、JAppletへのコンポーネント追加はinvokeAndWait()と覚えておいた方が良さそうだ。
…と理解したのだが、ログを出力して見ると、JNLPAppletLauncherで起動するJAppletのinit()はSwingのinitスレッドでなくevent dispatcherスレッドで動くようなので、invokeAndWait()も使わなくて良いと思うのだが、どうなのだろうか。
コメント