TeX Alchemist Online

TeX のこと,フォントのこと,Mac のこと

TikZによる連成振動アニメーション (3) 〜 動画投稿篇

以前の記事では,TikZによる連成振動アニメーションをGIFアニメに変換しました。
しかし,H.264などの現代的な動画形式などと異なり,GIFアニメは圧縮が全く効きませんので,ほんの数百フレームのアニメでも数MBもの巨大なファイルになってしまいます。

そこで,H.264の動画に変換した上で,「6秒動画」で知られるVineに投稿してみました。

動画に変換して投稿するまでの作業記録を記しておきます。
TeX Live 2014 on Mac OS X 10.9.4 で作業しました。

1. ImageMagick と FFmpeg の準備

MacPortsHomebrew を使うなどして,ImageMagick (convert) と FFmpeg をインストールします。
MacTeX または [改訂第6版]LaTeX2ε 美文書作成入門 からTeX環境をインストールした場合にはデフォルトで ImageMagick convert がインストールされています。

今回は MacPorts で FFmpeg をインストールしました。

$ sudo port install ffmpeg

2. TikZソースをコンパイルしてPDFを生成

Vineは「6秒アニメ」として知られていますが,厳密には,6.8秒の動画まで投稿できるようです。
30fpsの動画にするとすると,30*6.8=204フレームまで用意すればよいはずです。そこで,t=0,1,...,203 と変化させて,204ページのPDFを作成します。

\documentclass{minimal}
\usepackage[papersize={10.6cm,2.55cm},margin=1mm,noheadfoot]{geometry}
\usepackage{tikz}
\usetikzlibrary{calc,patterns,decorations.pathmorphing}
\usepackage[nomessages]{fp}
\pagestyle{empty}
\begin{document}

%%%% \A*cos(\OMEGA*\t)+\B*sin(1.73*\OMEGA*\t) のパラメータ
\def\A{1}
\def\B{0.8}
\def\OMEGA{0.2}

%%% 壁などの描画のパラメータ
\def\wallHeight{2}
\def\wallWidth{0.2}
\def\totalLength{10}
\def\springStraightLength{0.2}
\def\axisDepth{-0.7}

%%% 壁などのスタイル
\tikzset{wall/.style={pattern = north east lines}}
\tikzset{ball/.style={circle,shade,outer color=black!90!white,inner color=white,inner sep=2.5mm,label={$m$}}}
\tikzset{spring/.style={decorate,decoration={aspect=0.4, segment length=#1, amplitude=2mm,coil}}}
\tikzset{springk/.style={label={$k$},yshift=2}}

\foreach \t in {0,1,...,203}{%
\FPeval\u{\A*cos(\OMEGA*\t)+\B*sin(1.73*\OMEGA*\t)}%
\FPeval\v{\A*cos(\OMEGA*\t)-\B*sin(1.73*\OMEGA*\t)}%
\centering
\begin{tikzpicture}[>=stealth]
%%% 左壁
\coordinate (south east of left wall) at (0,-.5*\wallHeight);
\coordinate (north west of left wall) at ($(south east of left wall) + (-\wallWidth,\wallHeight)$);
\fill[wall] (south east of left wall) rectangle (north west of left wall);
\draw[thick] (south east of left wall) -- (south east of left wall |- north west of left wall);
%%% 右壁
\coordinate (south west of right wall) at (\totalLength,-.5*\wallHeight);
\coordinate (north east of right wall) at ($(south west of right wall) + (\wallWidth,\wallHeight)$);
\fill[wall] (south west of right wall) rectangle (north east of right wall);
\draw[thick] (south west of right wall) -- (south west of right wall |- north east of right wall);
%%% おもり
\node[ball] (a) at (\totalLength/3 + \u,0) {};
\node[ball] (b) at (2*\totalLength/3 + \v,0) {};
%%% 座標軸
\draw[->] (0.5,\axisDepth) -- +(\totalLength-1,0);
\draw[dotted,thick] (\totalLength/3,\axisDepth-0.3) -- +(0,1.6)
              (2*\totalLength/3,\axisDepth-0.3) -- +(0,1.6)
              (a.south |- south east of left wall) -- (a.south)
              (b.south |- south east of left wall) -- (b.south);
\draw[->] (\totalLength/3,\axisDepth-0.15) --node[below] {$x_1$} +(\u,0);
\draw[->] (2*\totalLength/3,\axisDepth-0.15) --node[below] {$x_2$} +(\v,0);
%%% 座標計算
\coordinate (0) at (0,0);
\coordinate (0-right) at (\springStraightLength,0);
\coordinate (a-left) at ($(a.west) + (0.1-\springStraightLength,0)$);
\coordinate (a-right) at ($(a.east) + (\springStraightLength,0)$);
\coordinate (b-left) at ($(b.west) + (0.1-\springStraightLength,0)$);
\coordinate (b-right) at ($(b.east) + (\springStraightLength,0)$);
\coordinate (c-left) at (\totalLength + 0.1-\springStraightLength,0);
\coordinate (c) at (\totalLength,0);
%%% バネの直線部
\draw (0) -- (0-right)
      (a-left) -- (a.west)
      (a.east) -- (a-right)
      (b-left) -- (b.west)
      (b.east) -- (b-right)
      (c-left) -- (c);
%%% バネのグルグル部
\draw[spring={\totalLength/3 + \u}] (0-right) -- node[springk]{} (a-left);
\draw[spring={\totalLength/3 + \v - \u}] (a-right) -- node[springk]{} (b-left);
\draw[spring={\totalLength/3 - \v}] (b-right) -- node[springk]{} (c-left);
\end{tikzpicture}
\newpage
}
\end{document}

上記ソース oscillation.tex を,pdfLaTeX でコンパイルします。

$ pdflatex oscillation

すると,204ページからなるパラパラ漫画PDFが生成されます。

3. ページごとに分割

ImageMagick の convert コマンドを使って,PDFをページごとのPNGファイルに分割します。

$ convert -debug all -alpha deactivate -density 300x300 -resize 800x oscillation.pdf oscillation.png

-alpha deactivate オプションを付けることで,PDFの背景にあたる部分を透過させることなく,背景を白色で塗りつぶしたPNG画像を生成させています。density や resize の値は目的に応じて適宜調整してください。

すると,oscillation-0.png ~ oscillation-203.png という連番の付いた204枚のPNG画像が生成されます。

4. MP4動画にする

FFmpegによって,フレームレート30fpsで,H.264で圧縮したMP4形式の動画を作成します。

$ ffmpeg -r 30 -i oscillation-%d.png -c:v libx264 -pix_fmt yuv420p oscillation.mp4

%dの部分が連番のフォーマットです。

GIFアニメだと約4.6MBの巨大ファイルになるのに対し,H.264だと圧縮がよく効くおかげで,たったの800KB程度の動画ファイルになります。

目論見通り,Vineの投稿できる動画の長さの限界値ちょうどである,6.8秒の動画になりました。