フォルダ投入型の分散処理システムを物理シミュレーションとBlenderレンダリングに拡張した話 後編

この記事について

前編では、input フォルダにファイルを入れるだけで、LAN内のワーカーPCが画像、PDF、OCR、動画処理を自動で実行する仕組みを作りました。

前編: フォルダに入れるだけでLAN内のPCが勝手に処理する分散処理システムを作った話

この記事はその後編です。

今回は、もう少し重めで面白い処理を追加しました。

physics_sim
blender_render
blender_animation

フォルダにJSONや .blend を置くと、ワーカーPCが物理シミュレーションやBlenderレンダリングを実行します。


追加したジョブ

追加後のワーカー能力は、だいたいこうなりました。

blender_animation
blender_render
image_grayscale
image_ocr
image_resize
image_thumbnail
pdf_ocr
pdf_to_images
physics_sim
video_thumbnail
video_transcode

前編の仕組みでは、サーバーが job_type を判定し、ワーカーは自分の capabilities に合うジョブだけを取得します。

なので、今回も同じ考え方で拡張しました。

input\physics\*.json
  -> physics_sim

input\blender\*.blend
  -> blender_render

input\blender-animation\*.blend
  -> blender_animation

物理シミュレーション

まず入れたのは physics_sim です。

これはJSONで初期条件を書いて、ワーカーがシミュレーションし、CSVとグラフPNGを返すジョブです。

例えば振り子ならこうです。

{
  "type": "pendulum",
  "length": 1.0,
  "gravity": 9.81,
  "theta0": 0.8,
  "omega0": 0.0,
  "duration": 10,
  "dt": 0.01
}

投入する場所はここです。

server\input\physics\pendulum_001.json

出力はこうなります。

server\output\pendulum_001_result_processed.csv
server\output\pendulum_001_plot_processed.png

対応したシミュレーションは、まずこの3つです。

pendulum
projectile
spring_mass

リアルタイムゲームの物理演算をPC間で同期するのは難しいです。 でも、こういうバッチ型のシミュレーションなら分散しやすいです。

条件の違うJSONを大量に置けば、複数ワーカーが順番に拾って結果を返してくれます。


Blender静止画レンダリング

次に blender_render を入れました。

これは .blend ファイルをワーカーPCのBlender CLIで開いて、1フレーム目をPNGとしてレンダリングするジョブです。

server\input\blender\scene.blend
  -> server\output\scene_frame_0001_processed.png

内部的には、だいたいこういうコマンドです。

blender -b scene.blend -o scene_frame_#### -F PNG -f 1

BlenderはGUIを開かなくても、-b でバックグラウンド実行できます。 これが分散ワーカーと相性が良いです。

ワーカー側では blender.exe がPATHから見える時だけ、能力に blender_render を追加します。

blender_render
  -> blender.exe が必要

Blenderアニメーションレンダリング

静止画ができるなら、次は動画です。

blender_animation では、.blend のアニメーションをPNG連番としてレンダリングし、FFmpegでMP4に結合します。

server\input\blender-animation\scene.blend
  -> server\output\scene_animation_processed.mp4

ここではBlenderだけでなくFFmpegも必要です。

blender_animation
  -> blender.exe と ffmpeg.exe が必要

そのため、ワーカーの能力判定も次のようにしました。

blender.exe がある
  -> blender_render

blender.exe と ffmpeg.exe がある
  -> blender_animation

Blenderはフレームを書き出す担当。 FFmpegは連番PNGをMP4にまとめる担当です。


公式blendファイルで詰まった

公式デモの blender-4.0-splash.blend を入れて試したところ、最初は認識されなかったり、失敗したりしました。

サーバーサービスが古いコードを読んでいた

まず、自動登録されない問題がありました。

ファイルはここにありました。

server\input\blender-animation\blender-4.0-splash.blend

でもジョブになりません。

原因は、メインサーバーが古いコードのままサービス起動していたことでした。 blender-animation フォルダを判定するコードを追加しても、サービスを再起動しないと反映されません。

Restart-Service DistributedOsLayerServer

サービス化していると、コードを直しただけでは反映されない。 これは当たり前ですが、実際にハマりやすいところでした。

Blenderの出力形式に引っ張られた

次に、ジョブとしては拾うけれど、レンダリング結果が出ない問題がありました。

ログにはこんなエラーが出ました。

blender finished but no rendered frames were found

調べると、blender-4.0-splash.blend はもともと出力形式が FFMPEG になっていました。

最初の実装では、Pythonスクリプトで出力形式を PNG に変えようとしていました。 でもBlender 5.1では、このファイルに対してPythonから PNG を設定しようとすると弾かれました。

そこで方針を変えました。

Pythonでレンダー設定を書き換えるのではなく、Blender CLIのオプションでPNG連番を出すようにしました。

blender -b scene.blend -o frame_#### -F PNG -s 1 -e 120 -a

その後、FFmpegでMP4に結合します。

ffmpeg -framerate 24 -i frame_%04d.png -c:v libx264 -pix_fmt yuv420p output.mp4

この方式の方が、.blend 側の元の出力設定に引っ張られにくくなります。


重いファイルは最大フレーム数を絞る

公式デモの blender-4.0-splash.blend は、1フレームだけでも約35秒かかりました。

そのまま210フレームを回すとかなり時間がかかります。

そこでMVPでは、アニメーションレンダリングの最大フレーム数を設定できるようにしました。

"blender_animation_max_frames": 120

短く試すなら、例えば24フレームにします。

"blender_animation_max_frames": 24

制限なしにしたい場合は 0 です。

"blender_animation_max_frames": 0

まず短いフレーム数で動作確認してから、本番レンダリングに入る方が安全です。


試す手順

テスト用の .blend はスクリプトで作れるようにしました。

静止画レンダリング用:

examples\blender\make-test-blend.cmd

アニメーションレンダリング用:

examples\blender\make-test-animation-blend.cmd

外部の .blend を使う場合は、置き場所で処理が変わります。

server\input\blender\scene.blend
  -> 静止画PNG

server\input\blender-animation\scene.blend
  -> MP4

ワーカー側では、サービス環境のPATHにBlenderとFFmpegの両方を入れます。

D:\Blender Foundation
C:\...\ffmpeg\bin

capabilities に次が出れば準備完了です。

blender_render
blender_animation

まとめ

前編で作った仕組みは、処理の中身を差し替えやすい構造でした。

サーバーはファイルを見て job_type を決める。 ワーカーは自分にできるジョブだけ取る。 結果はoutputへ戻す。

この形にしておくと、あとから重い処理を増やしやすいです。

今回追加したのは、物理シミュレーションとBlenderレンダリングでした。

physics_sim
blender_render
blender_animation

画像処理から始めた小さいMVPが、いつのまにかLAN内のレンダーファームっぽいものになってきました。

まだフレーム単位の本格分散レンダリングまではしていません。 でも、.blend をフォルダに入れたら別PCがレンダリングしてMP4を返すところまでは来ました。

こういう「普段使っているPCが、裏で少しずつ仕事を分け合う」感じはかなり面白いです。