📐

【DaVinci Resolve】 回転した四角形の計算【Fusion】

2025/02/15に公開
4

🐥 はじめに

みなさん、こんにちは。Mugです ✨

これは 📽DaVinci Resolveについての記事です
DaVinci Resolve の Fusion では Expression として計算式を設定できますが
それを使って回転した四角形の幅・高さを求める計算方法についての記事です

Width/Height
👆 やりたいのはこちら、黄色い四角形が収まるように青い四角形の幅・高さの計算する

Expression の基本的は計算は 👇 こっちを見てね 🐼
https://zenn.dev/muglab3/articles/1d32711f7eb419

🐦 回転した四角形の幅・高さを計算する

四角形を回転させたときの ➡️X 軸方向 の長さ、⬆️Y 軸方向の高さは
学校 🏫 で習うように 📐 三角関数で計算できますが、
DaVinci Resolve ではいくつか注意点があります ❗

三角関数に渡す角度は radian

Expression では 三角関数としてsin, cos, tan という関数が使えます
しかしこれらの関数が受け取る角度は radian です 😮
インスペクタのコントロールに入力する値は基本的に degree なので
degree から radian に ♻️ 変換してからsin, cos, tan に渡す必要があります
その時に使用するのがradという関数です 👍

60° を radian に変換する

rad(60)

👉 1.047

サイン、コサイン、タンジェント 💃

sin(rad(60))

👉 0.866

cos(rad(60))

👉 0.500

tan(rad(60))

👉 1.732

アスペクト比を考慮する

DaVinci Resolve では基本的に座標は全体を 1.0 とした相対座標となっています
これは縦・横どちらも同じです
そのためアスペクト比が 1:1 ではない場合、同じ値でも絶対的な大きさが縦と横で異なります
これがExpressionでサイズ計算を行う上で重要なポイントとなります 😤

👇 縦と横ともに 0.5 を設定しても 🟪 正方形にはならないよ 😮
rectangle
同じ値を設定しても長方形

アスペクト比計算

アスペクト比はcomp:GetPrefsを用いて
Comp.FrameFormat.WidthComp.FrameFormat.Heightから縦横サイズを取得して計算します

comp:GetPrefs("Comp.FrameFormat.Width")

👉 1920

comp:GetPrefs("Comp.FrameFormat.Height")

👉 1080

comp:GetPrefs("Comp.FrameFormat.Width") / comp:GetPrefs("Comp.FrameFormat.Height")

👉 1.777

これを高さ側にかけ合わせると🟪 正方形になります 👍

0.5 * (comp:GetPrefs("Comp.FrameFormat.Width") / comp:GetPrefs("Comp.FrameFormat.Height"))

square
高さにアスペクト比をかければ正方形

アスペクト比計算結果を覚えておく

アスペクト比はサイズの計算では頻繁に出てきます
それに 👆 のような長い式を毎回入れていると大変 😵‍💫 なので、
計算結果を覚えておいて簡単に使えるようにします

それにはself:SetData, self:GetDataを使用します

SetData

self:SetData("合言葉", 覚えておく値) です

self:SetData("aspectRatio", (comp:GetPrefs("Comp.FrameFormat.Width") / comp:GetPrefs("Comp.FrameFormat.Height")))

GetData

self:SetData("合言葉") です

self:GetData("aspectRatio")

👉 1.777

Start Render Script

ではどこでself:SetDataすればいいの?🤔 というと
計算式をいれる予定のノードStart Render Scriptです

Start Render Scriptでは rendering 開始時に実行したい処理を書くところなので
ここでアスペクト比を覚えておくようにします 😤

Start Render Script
Start Render Script の場所

👾 実践 👾

ここまでの内容を使って
四角形をピッタリ収めるような回転した四角形の高さを計算してみます‼️

Width/Height
👆 こちらが期待値です

🟨 黄色の四角形: Rectangle1
🟦 青色の四角形: Rectangle2

🟦 Rectangle2 の高さを調整します

2 つの部分に分けて考えて、それらを足してとします
幅を求めたいので三角関数のマイナス値側はいらないです 👻
abs関数を使って絶対値に変換します

紫の直角三角形から底辺部分(緑)

幅 1
幅 1

Rectangle1.Width * abs(cos(rad(Angle)))

紫の直角三角形から高さ部分(緑)

幅 2
幅 2

Rectangle1.Height * abs(sin(rad(Angle))) * (1 / self:GetData("aspectRatio"))

こちらはRectangle1.Heightをもとに計算するので、アスペクト比: self:GetData("aspectRatio")の逆数をかけます

結果

これらを足して、を求める式はこちらです 😤

(Rectangle1.Width * abs(cos(rad(Angle)))) + (Rectangle1.Height * abs(sin(rad(Angle))) * (1 / self:GetData("aspectRatio")))

高さ

高さも幅と同様に、2 つの部分に分けて考えて、それらを足して高さとします
高さの場合は前述のようにアスペクト比を考慮してアスペクト比: self:GetData("aspectRatio")をかけます

紫の直角三角形から高さ部分(緑)

高さ 1
高さ 1

Rectangle1.Width * abs(sin(rad(Angle))) * self:GetData("aspectRatio")

紫の直角三角形から底辺部分(緑)

高さ 2
高さ 2

Rectangle1.Height * abs(cos(rad(Angle))) * (1 / self:GetData("aspectRatio")) * self:GetData("aspectRatio")

こちらはRectangle1.Heightをもとに計算するので、アスペクト比: self:GetData("aspectRatio")の逆数をかけます

結果

これらを足して、高さを求める式はこちらです 😤

((Rectangle1.Width * abs(sin(rad(Angle)))) + (Rectangle1.Height * abs(cos(rad(Angle))) * (1 / self:GetData("aspectRatio")))) * self:GetData("aspectRatio")

Demo

https://x.com/MugLab3/status/1891890984268841229

🤏 おまけ

逆パターン 🙃
🟦 の四角形(Rectangle2)を
🟨 の四角形(Rectangle1)の中でぴったりサイズになるように回転させる計算式です

計算式

w1=Rectangle1.Width \\ h1=Rectangle1.Height
w2=Rectangle2.Width \\ h2=Rectangle2.Height
AR=self:GetData("aspectRatio")

とすると

w_2 = \frac{|\cos\theta| w_1 - |\sin\theta| h_1 \cdot \frac{1}{\text{AR}}}{\cos 2\theta}
h_2 = \frac{-|\sin\theta| w_1 + |\cos\theta| h_1 \cdot \frac{1}{\text{AR}}}{\cos 2\theta}\cdot \text{AR}

です

式の意味はわかりません 😭
外側の四角形を回す式を逆にしたということだと思いますが
よくわかりません 💦💦

デモ

この式では一部計算できない角度が発生するので表示が消えます
実際に回転させたい場合はアレンジが必要です 😎
https://x.com/i/status/1891888825871331816

表示できなくなる前に折り返すパターン
https://x.com/i/status/1891893090149073107

🐔 おわりに

ちょっとむずかしいね!🐼

GitHubで編集を提案

Discussion

よもぎよもぎ

関連ないですが、Transformノード「UseSizeAndAspect」チェックボックスで
設定項目切り替わるのですが、あれってどうやったら実現できるのでしょうか。
例)
1)CustomTool1にチェックボックスを追加。名前をChkUseAspect
2)CustomTool1にスライダー(Size,Aspect,XSize,YSize)を追加
ChkUseAspectがチェック時(=1,~=0)でSize,Aspectが設定項目が利用可能
ChkUseAspectが未チェック時(=0)でXSize,YSizeが利用可能。
Fuseでプラグインとして項目の表示・非表示可能なのは理解できるのですが、Expressionで設定項目の表示・非表示って切り替えできないのでしょうか。。

MugMug

Fuseじゃないと設定を切り替えたというイベントが取得できないので
同じようにはできないと思います😢
CustomToolだけで頑張る場合は、更にボタンを追加して
ボタンを押したらINPB_IC_Visibleを切り替えるようにするとそれっぽくはなります😊👍

👇 Button Controlのexcecuteへの設定例

comp:Lock()

local thisMacro = tool:GetAttrs('TOOLS_Name')
local thisTool = FindTool(thisMacro)
local visible = thisTool.Size:GetAttrs("INPB_IC_Visible")

thisTool.Size:SetAttrs({INPB_IC_Visible = not visible})
thisTool.Aspect:SetAttrs({INPB_IC_Visible = not visible})
thisTool.XSize:SetAttrs({INPB_IC_Visible = visible})
thisTool.YSize:SetAttrs({INPB_IC_Visible = visible})
if not visible then
    thisTool.ChangeButton:SetAttrs({ INPS_Name = "Size/Aspect"})
else
    thisTool.ChangeButton:SetAttrs({ INPS_Name = "X/Y Size"})
end

comp:Unlock()

参考情報
https://www.steakunderwater.com/wesuckless/viewtopic.php?t=4081

よもぎよもぎ

ご多用のところ。ご返答いただき誠にありがとうございます。
GUIの各種開発ツール(C#、Delphi)だと項目にVisible(Visiblity)などの属性があり、操作できる感覚ですので、その感覚のまま、あれやこれやとやっておりました。
今一度、リファレンスなど読み、回答していただいた内容も踏まえ、Fusion、Fuseをいじくりまわしたいと思います。