DaVinci Resolve Fusionスクリプト

DaVinci Resolve※1では、作業者がよく行う編集操作をスクリプト化して効率を上げることができます。
アニメーションの撮影を補助するため、スクリプトの活用に取り組みました。

Fusionスクリプトをアニメーション撮影に活用した例として、CLIP STUDIO PAINT※2や東映アニメーションデジタルタイムシート※3から出力した汎用デジタルタイムシート(xdts)のインポート機能を紹介します。


※1 Blackmagic Design の映像編集システム
※2 セルシス のデジタル作画ツール
※3 東映アニメーション のデジタルタイムシート編集ツール

DaVinci Resolveによるアニメーション制作

DaVinci Resolveは、様々な映像を造り出すことができる高機能な編集ツールです。
革新的な機能を提供していたり、高性能なカメラや専用キーボードなどのハードウェアも揃っているため、映像制作での導入事例が増えてきています。

リトルビットでは、アニメーション制作における活用方法を研究しています。
2019年にはスタッフがトレーナー認定を受け、アンバサダーとしての役割も担い始めました。
その後、DaVinci Resolveを導入された方や、導入を検討されている方から様々なご意見をいただきました。

中でもタイムシートの取り扱いは、アニメーション撮影特有の要素として意識する必要がありました。
タイムシートで指定されたタイミングをツールに適用していく作業では多くの手順が必要になります。
このような作業の効率化にはスクリプトが効果的なので、Fusionスクリプトによる開発に着手しました。

デジタルタイムシートのインポートスクリプト開発

Fusionスクリプトの理解

DaVinci Resolveでは、LuaおよびPythonで記述されたスクリプトがサポートされています。
Luaを利用するとツールのほとんどの機能を呼び出すことができ、ツールに初めから組み込まれていたこともあり、Luaでの記述を選択しました。

ツール上でスクリプトを呼び出す方法は以下のようになっています。

  1. スクリプトが記述されたファイルを既定のフォルダに配置します。
  2. ツールを起動すると、メインメニューの[ワークスペース]-[スクリプト]にファイル名のコマンドが追加されています。
  3. コマンドを実行します。(キーボードショートカットも適用できます)

特別な開発ツールは必要なく、テキストエディタがあれば機能を追加できてしまいます。
微修正が必要になった際もすぐに適用できるので、作業者自身が使いこなせるようになったら大きな強みになりそうです。
※ファイルを用いないスクリプトの活用方法もあります。

今回実現したい「デジタルタイムシートのインポート」に必要な機能は多数あります。
ファイル読み込みや解析はLuaの標準機能(バージョン5.1)を使って実装します。
目的に合ったライブラリが公開されていることもあるので、ライセンスに則って利用可能です。

DaVinci Resolveの機能を呼び出す方法は、サンプル・ドキュメントを参考にして実装していきます。
(ドキュメントは2016年に発行された英語版のみ)
開発者同士の交流も活発で、多くの汎用的な機能がスクリプト化されて配布されています。

タイムシートの情報を編集ツールのタイミング情報に

タイムシートに記述されている指示に基づいて、編集ツールの情報を構築していく必要があります。
スクリプトを記述する前に、DaVinci Resolveにおけるタイミング情報の適用手順を組み立てていきます。
このステップでは、作業者の方とコミュニケーションを取りながら要件と方法を整理していきました。
よりシンプルなノード構成を検討したり、扱うパラメータの種類を少なくするなど、編集作業全体のことも考慮します。

手順が組み立てられたらスクリプトの記述に移りますが、先にスクリプトの動作を紹介しておきます。

操作手順
  1. Fusionページを表示し、適用対象ノードの名称をタイムシートのセル名と一致させておきます。
  2. スクリプトを実行します。
  3. 表示されたダイアログで以下の項目を設定します。
    ・TargetMedia:適用対象ノード
    ・TimeSheetFile:デジタルタイムシートファイル(XDTS形式、StylosCSV形式)
  4. ダイアログの[OK]ボタンを押して、処理を実行します。

実行結果
  1. 図のようにTimeStretcher・MatteControl・Rectangleノードが追加されます。
  2. タイムシートで指定されたタイミングとセル番号を再現するため、TimeStretcherのSourceTimeパラメータにキーフレームが追加されます。
  3. タイムシートの空セルを再現するため、MatteControlのGarbageMatteに接続されたRectangleのLevelパラメータにキーフレームが追加されます。

このカーブだとセルの切替がクロスフェードになってしまいます。
セルアニメーションの表現をするにはカーブを直角にする必要があるため、すべてのキーフレームを選択して[Step In]ボタンを押します。


この編集操作はまだスクリプト化ができていません。
開発チームとのコミュニケーションをはかり、改善に取り組んでいます。

スクリプト紹介

今回記述したスクリプトを部分的に紹介します。
掲載コードは省略していますので、参考としてご覧ください。

ダイアログの表示

設定項目を構築して「composition:AskUser」を呼ぶと、ダイアログが表示されます。
今回のスクリプトで利用した設定項目は2種類だけですが、他にも数値入力スライダーやチェックボックス等が利用できます。
作業者の求めていることを対話して理解できるので、ダイアログが利用しやすいのはとても重要です。

--ダイアログ設定を構築.
local d = {}

--ダイアログ設定1:TargetMediaドロップダウン.
local targetMediaNames = {}
--[[ 省略 ]]--
d[1] = {"Target", Name = "TargetMedia", "Dropdown", Options = targetMediaNames, Default = default}

--ダイアログ設定2:TimeSheetFileファイル選択.
local composition_path = composition:GetAttrs().COMPS_FileName
d[2] = {"File", Name = "TimeSheetFile", "FileBrowse", Default = composition_path}

--ダイアログを表示.
local dialog = composition:AskUser("ImportTimeSheet", d)
if dialog == nil then
	os.exit()
end
デジタルタイムシートの解析

汎用デジタルタイムシート(xdts)はJSON形式で記述されているので、パースしてLuaのテーブルに変換します。
オープンなフォーマットなので、必要なデータへのアクセス方法は公開情報を参照すれば理解できます。

データをFusionページの編集時に扱いやすいように整理して、次のステップへ渡します。

--[[
	名称で指定されたセルのフレーム情報配列をタイムシートファイルから取得する.
]]
local function GetFrameInfoFromXDTS(pathTimeSheet, targetCelName)
	local frameInfo = {}

	--XDTSファイルをデコード.
	local decodeXDTS = DecodeXDTS(pathTimeSheet)
	if decodeXDTS then
		local timeTables = decodeXDTS["timeTables"]
		local fields = timeTables[1]["fields"]
		for fieldIndex = 1, #fields do
			--フィールドIDを確認.
			--  0 : セル番号.
			--  3 : 話者名とセリフのタイミング.
			--  5 : カメラワークの指示.
			local fieldID = fields[fieldIndex]["fieldId"]
			if 0 == fieldID then
				--[[ 省略 ]]--
			end
		end
	end
	return frameInfo
end

番号が記載されているコマの情報は、以下のように保持しておきます。

local frameNo = frame["frame"] + 1
local frameValue = frame["data"][1]["values"][1]
frameInfo[#frameInfo + 1] = {frameNo = frameNo, frameValue = frameValue}

「RETAS STUDIO Stylosから書き出されたタイムシートファイルも読み込みたい」と言うリクエストがあったので、ファイル読み込み・変換処理を実装しました。
汎用デジタルタイムシート(xdts)とは違いオープンなフォーマットではありませんが、タイムシートをCSV形式(カンマ区切り)へシンプルに変換したファイルとなっていますので、実際に出力されたデータを参照することでフォーマットを理解することができます。

ノードの作成と接続

ノードを作成したら、必要なパラメータに値を設定します。
意図したとおりに他ノードと接続されるよう、テスト実行しながらコードを記述していきます。
以下はRectangleの例です。

--Rectangleを追加.
local rectangle = composition:AddToolAction("RectangleMask")
rectangle:SetAttrs({TOOLS_Name = targetCelName.."_Rct"})	--名称を設定.
rectangle.Width = 1.0
rectangle.Height = 1.0

--追加したツールの接続を設定.
matteControl:ConnectInput("GarbageMatte", rectangle)
キーフレームの作成

Rectangleには、空セルを再現するためのキーフレームを適用します。
まずは「composition:BezierSpline」でスプラインを作成しておきます。
空セルかそうでないかが切り替わるタイミングを「nullKeys」にセットしておいたので、以下のように適用します。

rectangle.Level = composition:BezierSpline({})

local curveRectangle = rectangle.Level:GetConnectedOutput():GetTool()
curveRectangle:SetKeyFrames(nullKeys, true)

今後の展望

リトルビットは、新しいツールの導入を検討されている方に、メリット・デメリットの調査、課題を解決するソリューションの提供をできればと考えています。

アニメーション制作にDaVinci Resolveをご利用されている方、またはご興味を持たれている方がいらっしゃいましたら、お話を伺えると嬉しいです。