😽

フィルムルックは、グレインの量ではなく「なじみ方」で決まる

に公開

フィルムルックは、グレインの量ではなく「なじみ方」で決まります。

粒子を足すだけなら、実装は簡単です。ただし、粒子が映像の中に入って見えるには、色の応答、明るさごとの出方、粒子の大きさ、粒子の密度が同じ方向を向いている必要があります。そこがずれると、グレインを強くしてもフィルムらしさではなく、上から乗せたノイズに見えてしまいます。

Filmtone Desktop v1.13 では、この部分を native renderer 側で見直しました。

この記事では、まず「どう組むとフィルムルックに近づくのか」を整理し、そのあとで v1.13 で実装した Density Color Response、density-domain grain、Texture Engine の話に落とします。

フィルムルックはひとつの効果ではない

実装上は、フィルムルックをひとつのエフェクトとして扱いたくなります。

graded image + grain = film look

でも、この形だけだとすぐに限界が来ます。

実際に必要なのは、もう少し分解された関係です。

color response
  + density response
  + particle scale
  + particle density
  = image texture

色が先に硬く分離していると、そこに粒子を足しても質感にはなりません。明るい面と暗い面で粒子の見え方が同じだと、画面全体に均一な点が乗ったように見えます。Grain Size を上げたときに粒子の密度が変わらないと、大きい粒子ではなく粗いノイズに見えます。

つまり、見るべきなのは「グレイン量」だけではありません。

色、濃度、粒子サイズ、粒子密度の関係を組む必要があります。

RGB ノイズを足すだけだと何が起きるか

いちばん単純な実装は、graded image に RGB ノイズを足す形です。

output.rgb = graded.rgb + noise.rgb * amount

デバッグ用途なら分かりやすいです。ただ、見た目としては問題が出やすい。

このノイズは、下にある映像の状態を知りません。肌や緑、高彩度の色、深い黒がすでに硬く分かれている場合、ノイズはその破綻をさらに目立たせます。空や白い布のようななめらかな面では、映像の一部ではなく、上から散らした点に見えます。RGB が独立して動くと、粒子ではなく色付きの汚れに見えることもあります。

この問題は、amount を下げれば隠せます。

ただ、それでは欲しかった質感も消えます。直すべきなのはスライダーの値だけではなく、モデルの切り方です。

1. グレインの前に、色応答を整える

Filmtone Desktop v1.13 では、内蔵の Stone / Urban / Noir のレンダー経路に、内部的な Exposure / Density Color Response を入れました。

これは新しい UI ではありません。sidecar schema も変えていません。export workflow も変えていません。Imported LUT や custom grade path には、将来明示的に opt-in するまで勝手には適用しません。

目的は狭いです。

強いプリセットを当てたとき、色が先に割れていると、グレインはその割れを増幅します。なので、粒子を足す前に、built-in preset の中で色がどう粘るかを整えます。

実装としては、単にこう考えない。

LUT first, noise later

color response と grain response を、同じ renderer の中で見ます。

2. グレインを RGB ではなく density 側で扱う

次に見直したのが、グレインそのものです。

v1.13 では、built-in grain path を direct RGB noise ではなく、density-domain particle model に寄せています。

ここで言う density は、映像の明るさや濃さに対して粒子がどう見えるかを扱うための内部的な置き場所です。フィルム乳剤を丸ごと再現する、という意味ではありません。

方向性はこうです。

mostly luma / density residual
weak correlated dye variation
no independent RGB color dirt
procedural particle structure

主信号は luma / density 側に寄せます。chroma の揺れは、独立した RGB ノイズではなく、弱く相関した dye variation として扱います。

ここで避けたかったのは、粒子の汚さを被写体判定で隠すことです。肌だから守る、白い服だから消す、顔だから避ける、という説明にはしていません。まず粒子のモデル側を直します。

3. Texture Engine で「どこに出るか」と「何が出るか」を分ける

今回の大きい内部変更は、grain を次の形で扱う Texture Engine です。

Texture = ScalingField(image) * ParticleField(seed, params)

ScalingField は、texture がどこに見えるべきかを決めます。grain の場合は、image-dependent です。highlight、midtone、shadow で同じように粒子を出すわけではありません。

ParticleField は、texture そのものの形を決めます。粒子の大きさ、密度、ばらつき、stochastic structure をこちらに寄せます。

この分割が必要なのは、Grain Size が amount ではないからです。

Grain Size を上げたとき、単にノイズが粗く、強くなるだけだと、明るい面ではすぐに digital spray になります。サイズを上げるなら、粒子の密度も一緒に動かせる必要があります。

v1.13 では Grain Size を Texture Engine に通すことで、particle density と particle scale を交換できるようにしています。明るい面で、細かい点を増やすだけではなく、少ない大きめの粒子として読ませるためです。

流れとしてはこうです。

graded image
  |
  v
internal color / density response
  |
  v
ScalingField(image)         ParticleField(seed, params)
        |                          |
        +------ texture = scaling * particles
                           |
                           v
                 density-domain grain response
                           |
                           v
                       output image

なぜ UI を増やさなかったか

今回のリリースでは、グレイン専用パネルを追加していません。

既存の controls、保存済み設定、sidecar、export workflow はそのままです。変更したのは、Stone / Urban / Noir の built-in render path の下側です。

これは意図的です。

モデル側の失敗を、ユーザーに追加スライダーで補正させたくありませんでした。まずは、既存の Grain Size と grain parameter が、より妥当な内部モデルを通るようにする。そのほうが先です。

今回やっていないこと

境界も書いておきます。

Filmtone Desktop v1.13 は、フィルムストックシミュレーターそのものではありません。scanned grain plate library も入れていません。特定の film-emulation tool と同等、という比較もしていません。

Print Material speckBacklight Veil mottle も、このリリースで public texture surface になったわけではありません。Texture Engine の最初の公開用途は grain です。

また、これは Desktop v1.13 の public release に関する記事です。iOS の App Store 公開バージョンは別軸なので、この記事では iOS リリース告知としては扱いません。

まとめ

実装上の教訓は、かなり単純です。

film look の grain は、最後に足す noise layer ではなく、
image formation の一部として扱う必要がある。

そのために v1.13 では、色応答を先に整え、グレインを density-domain の particle model として扱い、ScalingFieldParticleField を分ける Texture Engine を入れました。

UI としては小さい更新です。新しいボタンも、schema bump もありません。

ただ、レンダリングの中では、グレインを「量」ではなく「映像の中でどう見えるか」として扱うための更新になっています。


実際の見え方を自分の素材で確認する場合:

Discussion