Java3DのInterpolatorを使ってみる

  • 投稿日:
  • by
  • カテゴリ:

アニメーションの制御をしてくれるInterpolatorは、デフォルトの設定で使うなら簡単で便利この上ないのだが、ちょっと思い通りに動作を変えようとすると、途端に調べる事と考える事が増える。お仕着せのシンプルなI/Fは融通が利かないというのは世の常である。簡単に使えるようになっているものでも、結局どういう時にどれくらい便利なのか、不都合な副作用が無いのかどうかを綿密に調べる羽目になることはよくある。

過去に何度か、簡単なアニメーションのためにInterpolatorを使おうとしたが、結局はやりたいことをやる方法がわからなくて、諦めてWakeupOnElapsedTimeを使って時間毎の処理を自前で書くことにしてきた。

しかし、賢い人達が練り上げた、OpenGLより上位のJava3DのI/Fが、不便であるはずが無い。必ず理由があってこのようなI/Fになっているはずである。私はすっかりSUNの信者である。使いこなせば便利で安全で堅牢で可般で最適で信頼性が高いに違いないことは、宇宙の真理として決まっているのである。
それにしてもInterpolatorを使ったアプレットはよくクラッシュする。
という訳で、一度きちんとInterpolatorを使う練習をしてみることにした。

テストアプリの起動ページへ
ソースコード

今回は、
・PositionInterpolator
・RotationInterpolator
・ScaleInterpolator
・ColorInterpolator
・TransparencyInterpolator
を使ってみた。

Interpolatorを使う上で最も多く問題になるのは、おそらく、アニメーションの周期や時間毎の動き方を決めるAlphaが作れるかどうかであろう。一定の速度で一方向に動かすだけなら簡単だが、加速・減速させたり、端まで行ったら折り返したり、端まで行ったら直角に進路変更させたりしようとすると、AlphaのI/Fをよく理解しないといけなくなる。

Alphaのコンストラクタには、一番多いもので10個の引数がある。

Alpha(int loopCount, int mode, long triggerTime, long phaseDelayDuration, long increasingAlphaDuration, long increasingAlphaRampDuration, long alphaAtOneDuration, long decreasingAlphaDuration, long decreasingAlphaRampDuration, long alphaAtZeroDuration)
これの5つ目以降が、移動、加速、減速に関するものである。
Alphaというのは基本的には最小値(default=0.0)から最大値(default=1.0)までの間を動く値である。Alphaの動きは、次のようになる。

時刻速度時刻(パラメータ表記)
(1)最小値0(1)
加速(+)
(2)max(+)(1) + increasingAlphaRampDuration / 2
等速(+)
(3)max(+)(4) - increasingAlphaRampDuration / 2
減速(+)
(4)最大値0(1) + increasingAlphaDuration
停止
(5)最大値0(4) + alphaAtOneDuration
加速(-)
(6)max(-)(5) + decreasingAlphaRampDuration / 2
等速(-)
(7)max(-)(8) - decreasingAlphaRampDuration / 2
減速(-)
(8)最小値0(5) + decreasingAlphaDuration
停止
(9)最小値0(8) + alphaAtZeroDuration

AlphaのmodeがINCREASING_ENABLEの時(default)は(1)-(5)が繰り返され、(INCREASING_ENABLE | DECREASING_ENABLE)の時は(1)-(9)が繰り返され、DECREASING_ENABLEの時は(5)-(9)が繰り返される。
従って、端まで行ったら折り返す、というのは、Alphaのmodeを(INCREASING_ENABLE | DECREASING_ENABLE)にすればできる。

残りの引数については、
loopCount: 繰り返しの回数(-1だと無限)
triggerTime: Alphaが内部で動き始める時刻
phaseDelayDuration: Alphaが内部で動き始めてから値が動き始めるまでの時間
のようである。


InterpolatorはCPUパワーを最大限に使おうとするので、今回のプログラムでは繰り返し回数を少なめに指定している。しかし、webブラウザ上でJavaアプレットを実行させると、ブラウザの再読み込みボタンを押してもJavaのクラスのリロードにはならない(リセットされない)ため、繰り返しが終わって停止してから再実行する術が無い。そのため、今回はリプレイするボタンを付け加えた。(完了したアニメーションだけが再開される)

試行錯誤しながらリプレイする方法を調べてると、Alphaは繰り返しが終わってもpause状態にはならないことがわかった。そのため、Alpha#resume()を呼ぶだけではAlphaは再び動かない。pause()してsetStartTime()してresume()すると再開するのだが、InterpolatorをdisableしないでAlphaをpause()してresume()すると残像が残ることがあるとの情報を目にした。Java 3DのAPI仕様書のAlphaのページにも"Since the alpha object is no longer paused, ..."という1文があるので、Alpha#pause()はあまり推奨されていない感じがする。
代わりに、強引に思えるが、System.currentTimeMillis()で取り出した時刻をsetStartTime()すると一発のようである。Java 3DのAPI仕様書のresume()の項でも、System.currentTimeMillis()を使って説明されているので、Alphaを使う上ではSystem.currentTimeMillis()を意識せざるを得ないと思う。