×

Arshes v1.16.0 「レンダリングパイプラインの改修」リリースノート

はじめに

7/4にv1.16.0をリリースした。

ベータテストの参加はこちらから。

Join the Arshes betaAvailable on iOStestflight.apple.com

サマリ

新機能

  • 露出補正のコントロール
  • マニュアルホワイトバランス
  • Display P3サポート
  • HEIFフォーマットのサポート

改善

  • カメラ画面のUIを一新した(2回目)

破壊的変更

  • レンダリングパイプラインの変更

レンダリングパイプラインの変更

今回のリリースで最も大きな変更であるレンダリングパイプラインの改修について説明したい。

左が変更前で、右が変更後のパイプラインになっている。 色は色空間を表していて、黄色が非線形で青が線形を意味する。

カメラ映像

iOSのカメラ入力は色空間を指定できるようになっている。 sRGB、Display P3、HLGなどのオプションがあるが、 いずれの場合もY’CbCrでテクスチャが提供される。

変更前のパイプライン

カメラの色空間はsRGBを使用する。Y’CbCrをRGB(sRGB)にした後にOETFの逆を当ててリニアにする。 フィルターステージで行われるカラーグレーディングは 32332^{3} のLUTを使用しており、暗部に精度を割く必要があるのでLogを当ててからLUTを参照する。 LUTの中身はリニアな世界で変換しており、出力もリニアになっている。

LUTの出力に”ガンマ”を適用してsRGBにした後にエフェクトステージに渡す。 したがって、エフェクトステージのシェーダーはノンリニアなワークフローになっている。 ノンリニアなワークフローでは例えば光を加算するような実装を素直に書けないという問題がある。

新しいパイプライン

カメラ入力の色空間はsRGBとDisplay P3をサポートする。 いずれの場合もリニアなRGBに変換してエフェクトステージに渡す。 エフェクトステージは入力、出力、バックバッファがすべてリニアになった。

エフェクトステージの後にフィルターステージを実行する。 カメラ入力は現在はSDRのみで値は0以上1以下だが、エフェクトステージの出力はシェーダー次第では1を超える可能性がある。

1を超えた値を保持したままカラーグレーディングを適用したいので、0以上4以下にクランプした後にLogを当てて、それからLUTを参照するようにした。 4という数字は勘で決めた値だが、真にHDRを前提にするなら16くらいまで上げる方がよさそう。 LUTに渡す値のレンジを広くするとLUTの精度が分配されることになり、バンディングが発生しやすくなるというデメリットがある。 HDRをやっていきたくなった場合はLUTの解像度を64364^{3}にできるようなオプションを用意すると良いかも。 ともかく、この辺の改善は挙動を維持しつつ行えるので、今回はこれで良いと判断した。

歴史的経緯

こうやって両者を見比べると、どう考えても新しい方が自然に見えるのだが、紆余曲折があり、理解が進んだ上でこういう形に落ち着いたように思う。 せっかくなので歴史的経緯などを説明する。

まず、当初はフィルターステージなどは存在しておらず、なんならカメラアプリというよりは「シェーダーアプリがカメラ映像も使える」みたいなノリだった。 シェーダーアプリなら return float4(uv, 0, 1)するといつものUVグラデーションが出て欲しいと思うわけで、そのためにはシェーダーの最終的な出力はsRGBになっている必要がある。 また、return cameraTex.Sample(s, uv) すればカメラの映像がそのまま出る方が自然でもある。 ここで、少し考えるとシェーダーはリニアワークフローにしつつ画面表示や画像の保存時にsRGBにするということを思いついても良いはずだが、特に何も考えず全部sRGBでやっていた。

その後、シェーダーでカメラ入力にエフェクトをかけるのが面白くなり、色々シェーダーを書くようになる。 すると、全てのシェーダーで輝度、コントラスト、彩度などを変更する処理を書く羽目になり、冗長なのでアプリの機能として切り出すことにした。これがフィルター機能である。 したがって、このフィルター機能はポスプロというよりはカメラ入力を調整する機能のはずなんだけど、アホなのでカラーグレーディング機能として、GPUでLUTを参照するような形で実装してしまった。

フィルターをエフェクトの前に置いたもう一つの理由として、フィルター適用後の値がバックバッファに格納されると、 エフェクトで return cameraTex.Sample(s, uv).rgb + backbuffer.Sample(s, uv).rgb としたときにフィルターが無限に重ねがけされてしまう、という話がある。

これはずっと困っていたポイントだったんだけど、冷静に考えるとフィルター適用前の状態をバックバッファに入れれば良いだけである。 この辺のパイプラインの話はDiscordで0b5vrさんに指摘されて、かなり整理が進んだように思う。 また色空間周りの取り扱いでは折登さんにも相談に乗ってもらい大変助かった。感謝。

次やること

Miroにやることリストみたいなのを並べて管理している。

4つの軸

  • 発見
    • 改善の余地があるがプリセットのアイデアを整理できていない
  • 呼び出し
    • 改善の余地があるがマイリストのアイデアを整理できていない
  • 撮影
    • 今回大きな変更を入れた
    • 露出マニュアルモードかHDRはやり得るがニッチっぽいので優先度が低い
  • 作成
    • Shader SpecはAR周りで改善の余地があるが枯れてきつつある
    • フィルターについてはトーンカーブが欲しい(全体 + RGBそれぞれ)

ストア公開の準備

  • ストア用のサムネイルを用意すれば審査には出せそう
  • Webをいい感じにしたい!

Continues

Continued by