読者です 読者をやめる 読者になる 読者になる

Interpolator で補間

JavaFX

この記事は、JavaFX Advent Calendar 2015 の 9 日目の記事です。

昨日も私の JCConf で JavaFX について発表してきた でした。

明日は @kokuzawa さんです

今日は小ネタ。

アニメーションで重要な概念に Interpolator があります。Interpolate が「補間する」という意味なので、Interpolator は「補間をするもの」ぐらいですかね。

コンピュータでアニメーションをする時は、ある時点での状態から、次の時点での状態を指定します。JavaFX で Timeline を使うのであれば、ある時点の状態を示すのが KeyFrame になります。

通常は複数の KeyFrame でアニメーションを行うわけですが、その KeyFrame 間の状態をどのようにつなげていくかということが補間です。

たとえば、移動する場合であれば、ある地点から他の地点へ移動する時に、等速運動で移動するのか、それとも重力落下のように等加速度運動で移動するのかなどさまざまな方法があります。等速運動で移動するのであれば、ある時点から次の時点までに 4 回の画面の書き換えがあれば、1 回の書きかえごとに 1/4 ずつ移動すればいいことになります。

実際には、何回の書き換えが行われるのかは GPU の性能などによって異なるため、補間曲線を定義しておきます。

通常、補間曲線は x 軸が時間、y 軸が状態の変化量を表すのですが、汎用的に使用できるように通常は開始点を原点、終了点を (1, 1) の点とします。

たとえば、等速運動だとこんな補間曲線になります。

この補間曲線があれば、どのように補間すればいいかすぐに分かるわけです。そして、これを保持しているのが Interpolator というわけです。

ところで、自然界で等速運動はあまり見かけることはありません。動作のしはじめはゆっくりなど、動作によって非線形に状態の変化が起こります。

よく使われるのが、はじめゆっくり、さいごゆっくり、はじめとさいごの両方ゆっくりという 3 種類です。たとえば、車が発進する時はアクセルを踏んでゆっくり加速しはじめ、途中は等速運動、さいごはブレーキを踏んでゆっくり止まります。これは、はじめとさいごの両方ゆっくりに当てはまります。

で、この 3 種類は一般的に Ease In、Ease Out、Ease Both (Ease In Out ということもあります) と呼ばれます。Interpolator クラスにもこの 3 種類はそれぞれ EASE_IN、EASE_OUT、EASE_BOTH と定数定義されています。

そのほかに、等速運動を表す LINEAR と、セルアニメーションのように離散的に状態が変化する DISCRETE の、合計 5 種類が定数として定義されています。

それぞれの定数の補間曲線で描いてみましょう。

EASE_IN

EASE_OUT

EASE_BOTH

DISCRETE

この 5 種類がどのように補間されているのか理解するには、実際にアニメーションにしてみるのが手っとり早いです。

5 種類並べて同時に移動させた結果がこちら。プログラムはさいごに載せました。

ちなみに、Timeline では LINEAR がデフォルト、Transition では EASE_BOTH がデフォルトになっています。

ここまでが前振りで、ここからが本題です。

この Interpolator は自分で任意の補間曲線を設定することができます。設定するには SPLINE メソッドか、TANGENT メソッドを使用します。ここでは、SPLINE メソッドを使用します。

SPLINE メソッドは開始点 (0, 0) と終了点 (1, 1) を通るスプライン曲線を補間曲線として設定するメソッドです。引数は 3 次スプライン曲線なので、引数は 2 つのコントロールポイントの座標になります。それを図示したのが、下図です。

たとえば、EASE_BOTH とは逆にロケットスタートして中だるみ、さいごにまたダッシュするような Inerpolator であれば、こんな感じで設定できます。

    Interpolator interpolator = Interpolator.SPLINE(0.2, 0.8, 0.8, 0.2);

で、なんで補間のことを話題にしているかというと、補間関数を下の図のようにして、予備動作を実現できないかと考えたわけです。

予備動作というのは英語だと anticipation といって、何らかの動作を行う前にする動作のことです。これはアニメーションのバイブルともいえる Disney Animation: The Illusion of Life に書かれている 12 の原則の 1 つなのです。下のリンクは英語版の方ですが、日本語版もあります。

The Illusion of Life (Disney Editions Deluxe)

The Illusion of Life (Disney Editions Deluxe)

下の図のように走り出すドナルドがちょっと後ろに体重をかけて、これからロケットスタートをするぞという動作です。アニメではよくある表現ですよね。

http://www.viz.tamu.edu/faculty/parke/ends489f00/section6/donald.gif
The Twelve Principles of Animationより引用

で、上の図のようにはじめマイナス側に補間する補間関数であれば、この予備動作ができるのではと思ったわけです。

で、やってみました。

    Interpolator interpolator = Interpolator.SPLINE(0.2, -1.0, 0.6, 0.6);

そうしたら、怒られちゃいました...

Caused by: java.lang.IllegalArgumentException: Control point coordinates must all be in range [0,1]
	at com.sun.scenario.animation.SplineInterpolator.<init>(SplineInterpolator.java:98)
	at javafx.animation.Interpolator.SPLINE(Interpolator.java:199)
	at InterpolatorDemo.start(InterpolatorDemo.java:26)

どうやら、コントロールポイントの座標は (0, 0) と (1, 1) の四角の中だけのようです。楽して予備動作をしようと思ったのに、残念。

もちろん、複数の KeyFrame、もしくは複数の Transition を SequentialTransition でつなげたアニメーションを使えば予備動作できるんですけどね。

簡単にできないかなぁと思ったわけです。まぁ、そんなに楽してはできないというのが、今日の教訓でした。

長くなってしまったわりには、内容がないエントリーだ ><


Interpolator Demonstration