POV-Rayでのアニメーションの作り方

# はじめに
これは [POV-Rayによる数学お絵かき入門 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/povray4math) の9日目の記事です.

今日の記事ではPOV-Rayでアニメーションを作る方法を述べます.

![](https://media.giphy.com/media/xUOxeUL0pwqz0NbyNy/giphy.gif)

# 最初の例
POV-Rayではアニメーションを作るための変数`clock`が用意されています.
この変数を使うためにはコマンドライン引数に`+KFFn`を与えます. (nには自然数が入ります)
コマンドライン引数はpovray.iniに書けば良い([第3回](https://qiita.com/Hyrodium/items/aeabdd9ab4c0a0de2788))のでしたから, 例えば次のように書いてみましょう.

```ini:povray.ini
Width=400
Height=300
Antialias=On
+KFF11
```

このように設定してpovファイルをレンダリングすると, 11枚の連番画像が生成されます.
この連番画像の過程で変化しているパラメータが`clock`であり, デフォルトで$0$から$1$までに線形に変化します.
今回の例では連番最初での`clock`の値は`0.0`であり, 順に`0.1`ずつ増えて連番最後では`1.0`の値になっています.

ここで具体例を1つ上げます.
次のコードをレンダリングすると連番画像が得られます.

```Povray:clock1.pov
camera{
    location <4,2,4>
    look_at <0,0,0>
}
light_source{
    <2,3,4>
    color rgb<1,1,1>
}
background{rgb<1,1,1>}
sphere{<0,0,clock>,0.2}
```

次節で連番画像からgifアニメーションに変換方法を述べます.

## gifアニメーションの作り方
gifアニメーションへの変換はImageMagicで出来ます.
今回の例ではコマンドラインで次のように入力します.

```
convert -delay 10 clock1*.png movie.gif
```

出力画像は次です.

![](https://i.imgur.com/GK7fRzt.gif)

Windowsであればgiamを使えばGUIで作成する事も可能です.


## frame_number
ここで`clock`と同程度重要な`frame_number`, `initial_frame`, `final_frame`を次に紹介します.

* `frame_number` : 連番画像毎に変わる変数.
* `initial_frame` : 連番最初の番号. デフォルトで`1`.
* `final_frame` : 連番最後の番号. `KFFn`で指定した`n`.

`clock`はデフォルトでは`(frame_number-1)/(final_frame-initial_frame)`に等しいです.

`frame_number`の有用性は第15回に予定している2重振り子の作例が分り易いと思います.

他のパラメータやアニメーションのコマンドラインオプションに関する情報は以下にあります.
http://www.povray.org/documentation/3.7.0/r3_2.html#r3_2_1
http://www.povray.org/documentation/3.7.0/r3_3.html#r3_3_1_5

# easing tips
easingとは物体の動きを自然に見せるの手法の事です.
例えば次のサイトが参考になると思います.
http://easings.net/ja

POV-Rayで作るアニメーションでは, 複数の動きを如何にして滑らかに繋ぐかが問題になります.
例えば以下の例では, パラメータに$\sin$を与えて滑らかに繋いでいます.
![](https://media.giphy.com/media/3o6gbfJCCdcGc0njH2/giphy.gif)

上の例のような単なる往復に関しては$\sin$で十分でしたが, 次のような複雑な動きを伴う場合にはそう上手く行きません.

![](https://media.giphy.com/media/xT0BKxXZN9eM1jbOuY/giphy.gif)

(ちなみに, 上画像は$\sum k^3$の可視化です: http://hyrodium.tumblr.com/post/94237657514)

以下では大体の状況で使える便利な関数を紹介します.

```math
\begin{align}
f(x)&=\begin{cases}e^{-\frac{1}{x}} &(x>0) \\0&(x\le 0)\end{cases} \\
g(x)&=\frac{f\left(\frac{2}{\sqrt{3}}x\right)}{f\left(\frac{2}{\sqrt{3}}x\right)+f\left(\frac{2}{\sqrt{3}}(1-x)\right)} \\
h_{(a,b)}(x)&=g\left(\frac{x-a}{b-a}\right)
\end{align}
```

これらの関数は次の性質があります.

* $f\in C^\infty(\mathbb{R})$が成り立つ.
* $g\in C^\infty(\mathbb{R})$は区間$[0,1]$で単調増加, $(-\infty, 0]$で常に$0$, $[1,+\infty)$で常に$1$を返す.
* $h_{(a,b)}\in C^\infty(\mathbb{R})$は区間$[a,b]$で単調増加, $(-\infty, a]$で常に$0$, $[b,+\infty)$で常に$1$を返す.

Desmosで描いたグラフは次です.
![](https://i.imgur.com/RfYsDp6.png)
https://www.desmos.com/calculator/6aymjmlpot

関数$g$での$\frac{2}{\sqrt{3}}$は変曲点で滑らかに繋ぐための係数です.

これをPOV-Rayのmacroで書けば次のようになります.

```
#macro smootha(a)
	#if(a>0)
		#local b=exp(-1/a);
	#else
		#local b=0;
	#end
	b
#end

#macro usmooth(a,b,s)
	smootha((2/sqrt(3))*((s-a)/(b-a)))/(smootha((2/sqrt(3))*((s-a)/(b-a)))+smootha((2/sqrt(3))*(1-(s-a)/(b-a))))
#end
```

この`usmooth`が上で定義した$h$に相当します.
関数$h$は区間$(a,b)$で単調増加でかつ, $a,b$において定数関数と滑らかに繋がっているため都合が良いという訳です.


### 具体例

![](https://media.giphy.com/media/xUOxeUL0pwqz0NbyNy/giphy.gif)

上から順に

* 等速運動
* 単振動 (正弦関数 $\sin$)
* `usmooth`

のアニメーションです.

この出力のためのコードは次です.

```
camera{
    orthographic
    location <0,0,10>
    right -3*x
    up 1.5*y
    sky y
    look_at <0,0,0>
}
light_source{
    <0,0,10>
    color rgb<1,1,1>
    parallel
    point_at 0
}
background{rgb<1,1,1>}

#macro smootha(a)
	#if(a>0)
		#local b=exp(-1/a);
	#else
		#local b=0;
	#end
	b
#end

#macro usmooth(a,b,s)
	smootha((2/sqrt(3))*((s-a)/(b-a)))/(smootha((2/sqrt(3))*((s-a)/(b-a)))+smootha((2/sqrt(3))*(1-(s-a)/(b-a))))
#end

#declare Time=2*clock;

sphere{<2*abs(Time-1)-1,0.5,0>,0.2}
sphere{<cos(pi*Time),0,0>,0.2}
sphere{<1-2*usmooth(0,1,Time)+2*usmooth(1,2,Time),-0.5,0>,0.2}
```