これまでの記事では、
scene-referred環境におけるLUTやCDLの位置づけについて整理してきました。

今回はその前提を踏まえ、
Flameでショット単位のCDLをどのように扱うかを整理していきます。

Context Variablesを使ったconfig.ocioの構成

今回のCDL運用では、.ccファイルを手動で選ぶのではなく、SHOTという変数で参照先を切り替えるようにしています。
この仕組みを作るのが、config.ocioの役割です。

考え方はシンプルです。

SHOT = A003C013_220415_R07B
↓
A003C013_220415_R07B.cc ----> 読む

つまり、CDLそのものを固定で書くのではなく、変数経由で動的に参照するようにしています。

この形にしておくと、

  • ショットごとのCDL切り替えができる
  • .ccファイルを差し替えても構成を変えなくていい
  • View確認と出力を同じソースで管理できる

という利点があります。

environment:

まず、変数SHOTを定義します。

environment:
  SHOT: default

ここでのdefaultは、初期状態やフェイルセーフ用です。
まだショットが選ばれていないときや、該当する.ccファイルを明示的に使わない状態では、
default.ccを読むようにします。

この1行があることで、SHOT未設定時でも構成が破綻しません。

search_path:

次に、.ccファイルを探しにいく場所を指定します。

search_path: "cc" ----> どこから探すか

今回の構成では、config.ocioと同じ階層にccディレクトリを配置し、
その中に各ショットの.ccファイルを格納しています。

Figo:~ admin$ tree /Volumes/StorageMedia/Apple_Project/Context_Variable/setups/colour_mgmt/Custom
/Volumes/StorageMedia/Apple_Project/Context_Variable/setups/colour_mgmt/Custom
├── cc
│   ├── A001C002_0904242F.cc
│   ├── A003C013_220415_R07B.cc
│   ├── A186C5021.cc
│   ├── A220C4928.cc
│   ├── A541C4691.cc
│   ├── A698C1627.cc
│   ├── A797C3822.cc
│   ├── A814C7486.cc
│   ├── A835C9876.cc
│   ├── A962C5353.cc
│   ├── B004C0023.cc
│   ├── B079C3839.cc
│   ├── B168C6496.cc
│   ├── B205C8416.cc
│   ├── B212C0102.cc
│   ├── B274C2342.cc
│   ├── B335C0546.cc
│   ├── B608C8921.cc
│   ├── B840C0187.cc
│   ├── B943C4492.cc
│   ├── C069C3907.cc
│   ├── C301C9619.cc
│   ├── C302C7261.cc
│   ├── C337C8400.cc
│   ├── C348C1571.cc
│   ├── C349C6046.cc
│   ├── C406C0929.cc
│   ├── C412C1090.cc
│   ├── C453C5665.cc
│   ├── C459C7999.cc
│   ├── C571C7397.cc
│   ├── C813C7472.cc
│   ├── C849C8705.cc
│   └── default.cc
├── ccc_to_cc_split.py
├── edit_33.ccc
├── studio-config-v3.0.0_aces-v2.0_ocio-v2.4_context.ocio
└── studio-config-v3.0.0_aces-v2.0_ocio-v2.4.ocio

2 directories, 38 files
Figo:~ admin$ 

この設定により、config.ocioはccディレクトリからファイルを検索するようになります。

Look

実際に.ccファイルを読むのはLookです。

looks:
  - !<Look>
    name: cdl_per_shot ----> Preferences > Project > Colour Management > Views > Looksに表示する名前
    process_space: ACEScct
    transform: !<FileTransform>
      src: "${SHOT}.cc"
      interpolation: linear

2つ重要な要素があります。

・ src: “${SHOT}.cc”

ここがContext Variablesの中心です。
SHOT変数の値に応じて読み込むファイルを切り替える仕組みになっています。

・ process_space: ACEScct

今回の検証では、DaVinci Resolveで作ったCDLとFlameの見た目を揃えるために、
ACEScgではなくACEScctで処理する必要がありました。

つまりこのLookは、単に.ccファイルを読むだけではなく、
どの色空間でCDLを評価するかまで含めて定義していることになります。

View

Lookを実際にFlameビューポートで表示させるためのViewを追加します。
今回は、ACES 2.0 – SDR 100 nits (Rec.709)のViewを複製後、cdl_per_shot(Look)を追加しました。

shared_views:
  - !<View> {name: ACES 2.0 - SDR 100 nits + CDL, view_transform: ACES 2.0 - SDR 100 nits (Rec.709), display_colorspace: <USE_DISPLAY_NAME>, looks: cdl_per_shot}

つまり、見たはRec.709 SDR表示ですが、その手前で.ccファイルが適用されます。

Display / active_views

Viewを定義しただけでは、Flame UIから選択することができない場合があります。

該当displayに登録

displays:
  Rec.1886 Rec.709 - Display: ----> Preferences > Project > Colour Management > Monitors
    - !<View> {name: Raw, colorspace: Raw}
    - !<View> {ACES 2.0 - SDR 100 nits (Rec.709), ACES 2.0 - SDR 100 nits + CDL, Un-tone-mapped}

active_viewsに登録

active_views: {ACES 2.0 - HDR 1000 nits (P3 D65), ACES 2.0 - HDR 1000 nits (Rec.2020), ACES 2.0 - HDR 2000 nits (P3 D65), ACES 2.0 - HDR 2000 nits (Rec.2020), ACES 2.0 - HDR 4000 nits (P3 D65), ACES 2.0 - HDR 4000 nits (Rec.2020), ACES 2.0 - HDR 500 nits (P3 D65), ACES 2.0 - HDR 500 nits (Rec.2020), ACES 2.0 - HDR 108 nits (P3 D65), ACES 2.0 - SDR 100 nits (P3 D65), ACES 2.0 - SDR 100 nits (Rec.709), ACES 2.0 - SDR 100 nits + CDL, Un-tone-mapped, Raw}

config.ocio設定は以上です。

次に、Flame UIから確認してみます。

View / Lookの確認

編集したconfig.ocioをプロジェクトにロード

Preferences > Project > Colour Management > Views

追加したViewとLookが正しく認識されているか確認

Flameビューポート

  • ACES 2.0 – SDR 100 nits + CDL
  • cdl_per_shot (ビューポートではLook)

Preferences > Project > Colour Management > Context Variables

config.ocioリフレッシュ時には、default (default.cc)がロードされます。

Figo:cc admin$ cat default.cc ----> CDL初期値
<?xml version='1.0' encoding='UTF-8'?>
<ColorCorrection id="default">
  <SOPNode>
    <Slope>1.0 1.0 1.0</Slope>
    <Offset>0.0 0.0 0.0</Offset>
    <Power>1.0 1.0 1.0</Power>
  </SOPNode>
  <SatNode>
    <Saturation>1.0</Saturation>
  </SatNode>
</ColorCorrection>Figo:cc admin$ 

ここでまず、手動でLook(.ccファイル)を切り替えてみます。

Context Variables > クリップネームに変更

ショットごとに異なるLook(.ccファイル)が適用されます。

この段階では、

  • TimelineFXノードは追加していない
  • ベイクもしていない

データに影響を与えず、ビューポート上の見た目だけが変化している状態です。

Context Variablesは再生ヘッドに連動しない

わかりやすく説明したいので、確認用.ccを追加しました。

  • RED_TEST
  • GREEN_TEST
  • BLUE_TEST

Context Variables > BLUE_TESTに変更

シーケンスセグメント移動

Context Variables > GREEN_TESTに変更

ここで注意したいのは、今回の構成では再生ヘッドを移動しても自動的にLook(.ccファイル)が
切り替わるわけではない ことです。

ACES 2.0 – SDR 100 nits + CDLから参照しているLookは、タイムライン上の各セグメントではなく、
その時点でContext Variablesに設定されているLook(.ccファイル)の値です。

つまり、Flameのビューポートには、.ccファイルが1つだけ適用されます。

SHOT = GREEN_TEST
↓
GREEN_TEST.cc ----> 表示に使用

そのため、再生ヘッドを別のセグメントに移動しても、表示されるLook(.ccファイル)は変わりません。

一般的な運用との違い

ここまでの構成を見ると、
CDLをLookノードとして適用するのではなく、Viewの中で処理している点に違和感を感じるかもしれません。

オートデスク社のLearning Channelなどで紹介されている一般的なワークフローでは、
CDLは「処理の一部」として扱われることが前提になっています。

Viewベースである理由

今回の構成では、CDLをLookノードとして処理に組み込むのではなく、
View(表示側)で適用しています。

これは、前回まで整理してきた通り、

  • CDLは最終ルックではなく調整(intermediate)
  • 最終的な見え方はdisplayで決まる

という前提に基づいています。

つまり、「調整(CDL)」と「見え方(View)」を分離するという考え方です。

今回のCDLは、あくまで「確認用の見え方」として切り離しています。

自動化が必要

この構成では、再生ヘッドに連動しないため、
今見ているショットに応じてLook(.ccファイル)を更新する必要があります。

次は、このSHOTの切り替えを、選択したセグメントやクリップに応じて自動化していきます。

Pythonによる自動化(タイムラインセグメント)

今回やることはシンプルで、
シーケンスセグメントにリンクしているクリップのクリップネームを取得し、
その名前をSHOTとして設定するだけです。

これにより、.cccのCCCIDとも一致しやすくなり、
シーケンスセグメントとBatchで同じルールを使うことができます。

まず、選択しているクリップの名前を取得します。

shot = seg.source_name.strip()

取得した名前は、そのままSHOTとして使用されます。

以下が実際に使用しているスクリプトです。
最小構成の例として記載しています。

set_shot_from_selected_segment.py
import flame

DEFAULT_SHOT_NAME = "default"

def _set_shot_context(shot_name):
    proj = flame.project.current_project

    if not shot_name:
        raise RuntimeError("SHOT名が空です")

    proj.set_context_variable("SHOT", shot_name)
    proj.reload_ocio_config()

    print("SHOT =", shot_name)
    print("contexts =", proj.get_context_variables())


# -------------------------------
# セグメント → Clip Name
# -------------------------------
def set_shot_from_selected_segment(selection):
    selected_segments = []

    for item in selection:
        if isinstance(item, flame.PySegment):
            try:
                if str(item.type) == "Video Segment":
                    selected_segments.append(item)
            except Exception:
                pass

    if not selected_segments:
        raise RuntimeError("ショットを1つ選択して右クリックしてください")

    seg = selected_segments[0]

    try:
        shot = seg.source_name.strip()
    except Exception:
        raise RuntimeError("接続クリップの名前を取得できません")

    if not shot:
        raise RuntimeError("クリップ名が空です")

    print("segment =", seg.name.get_value())
    print("clip_name =", shot)

    _set_shot_context(shot)


# -------------------------------
# Default
# -------------------------------
def set_default_cc(selection):
    _set_shot_context(DEFAULT_SHOT_NAME)


# -------------------------------
# UI表示条件
# -------------------------------
def is_segment(selection):
    for item in selection:
        if isinstance(item, flame.PySegment):
            return True
    return False


def always_visible(selection):
    return True


# -------------------------------
# メニュー
# -------------------------------
def get_timeline_custom_ui_actions():
    return [
        {
            "name": "Shot_CDL_Tools",
            "actions": [
                {
                    "name": "Set_Selected_Segment",
                    "isVisible": is_segment,
                    "execute": set_shot_from_selected_segment,
                    "minimumVersion": "2026.0",
                },
                {
                    "name": "Set_Default_CC",
                    "isVisible": always_visible,
                    "execute": set_default_cc,
                    "minimumVersion": "2026.0",
                },
            ],
        }
    ]

なお、デフォルト状態に戻すために「Set Default CC」も用意しています。
確認用や初期状態に戻す際に使用します。

まとめ

ここまでで、シーケンス上でショットごとのCDLを切り替える仕組みが整いました。

Context Variablesとconfig.ocioによって表示側でCDLを管理し、
PythonスクリプトからSHOTを切り替えることで、データはそのまま、見た目だけが変化している状態になります。

次の記事では、この仕組みをBatchショットベース運用に展開していきます。