SL 内でオブジェクトを動かしたり形を変えるようなときイージングというアニメーションの定番的な方法を使うともっともらしいです。
物を動かすとき最初はゆっくりしか動かず はずみがつくと速くなって 止まるときはまたゆっくり というような感じです。
(参照: Prototype easing curves)
SL スクリプトにはそういう仕組みが用意されてないようなので作ってみました。
作り方はベジエ曲線という数学的な曲線(wikipedia Bézier curve)の描き方があって その曲線が時間経過と位置や大きさの関係を表します。
よく使われるのは3次ベジエ曲線/Cubic Bezier Curve で 4つの点 P0,P1,P2,P3 のうち P0=(0,0), P3=(1,1) は固定であとの P1と P2 の設定で 0 から 1 までの時間と変化の関係を決めます。
計算式は B = (1-t)3P0+3(1-t)2tP1+3(1-t)t2P2+t3P3
スクリプトで書けば
vector cubicBezier(float t) { float t1 = 1.0 - t; return t1*t1*t1*P0 + 3.0*t1*t1*t*P1 + 3.0*t1*t*t*P2 + t*t*t*P3; }
ところで曲線を描くのに時間要素 t を変化させますが これは結果の曲線(x,y)の x: アニメーションの経過時間とは微妙に違います。
そこで描いた曲線 (x,y) からアニメーションの経過時間 t に等しい x に対応する変化量 y の値を 計算するには 曲線上の前後の点から補間します。
float easing(integer i) { if (i<=0) return 0.0; // 最初 else if (N<=i) return 1.0; // 最後 float t = (float)i/(float)N; // 経過時間→曲線を描くときにも使う vector b = cubicBezier(t); // 描いた曲線上の点 if (t<=b.x) --i; // 1つ前 else ++i; // 1つ後ろ float t0 = (float)i/(float)N; vector b0 = cubicBezier(t0); // 曲線上の隣の点 float r = (b.x-t)/(b.x-b0.x); // 時間の差と隣までの差の比率 vector br = b - r*(b-b0); // 補間した経過時間の曲線上の点 return br.y; }
補間計算のための数値は前後1つ隣しか見てませんが 同じ数で時間を刻めば描いた曲線の点も経過時間に近くて 変化が激しくなければ誤差もきっと小さいでしょう。
このアニメーションは lovemax ベネチア店の最上階 お城のデモを見に行く箱に仕込みました。
ほかにももう一つ わざとわかりにくくした場所にも仕掛けてますが 怪しいところを探せばきっと…。