kugi's notebook

やったこと、思ったことなどつらつらと書きます

レイトレ合宿10参加レポート

はじめに

10月11日(金)から10月13日(日)に初島で開催されたレイトレ合宿10に参加してきました! こちらはレイトレ合宿までの準備と当日の振り返り記事になります。

レイトレ合宿に参加するまで

レイトレ合宿は自作レンダラーで描画されたレンダリング結果(動画作品/画像作品)の美しさを競うオフライン集会です。 参加者は事前にレンダラーを提出し、合宿当日は作品の発表やセミナー、レクリエーションなどを行います。

今年は初島で開催されました!

カモメが出迎えてくれました

私はレイトレ合宿8レイトレ合宿9と参加し、今回で3回目の参加となりました。

過去の参加レポート

まずは「今回の目標」から共有したいと思います。

今回の目標

今回の目標は、『ハードウェアレイトレーシングに入門する』でした。

レイトレ合宿8では、

レイトレ合宿9では、

CPU 、GPU (ComputeShader) ときたので、 今年はレイトレーシングパイプラインに挑戦してみたいと思い、 DirectX Raytracing(DXR)を用いてハードウェアレイトレーシングに入門しました。

制作の過程

今回も制作までの記録をNotionにメモ書きとして残していきました。

Notionで制作の過程を記録

前回、前々回と比べると若干スロースタートでした...

レギュレーションとしては制限時間256秒。

今回は静止画も提出可能ではありましたが、 今回も動画を作りたかったので、レギュレーション最高枚数である画像600枚(10秒 60fps)を目指し進めました。

DirectX Raytracing Programming Vol.1

まずは技術書典12で購入したtechbitoさんの『DirectX Raytracing Programming Vol.1』を読みながらサンプルを動かしつつ入門し始めました。

booth.pm

とはいえ、DirectX12に触れるのも初めてだったため、序盤はドキュメント、DirectX12の参考書やブログ記事を参考にまずはレイトレでの三角形の描画を目標に進めていきました。

三角形描画まで

初めて触れる内容が多かったこともありCMakeでシェーダーコンパイルするための記述やGPUハンドルのオフセット忘れなど、つまづくことが多かったです。

ようやく三角形描画までのパイプライン実装まで終わったと思った矢先、 背景は描画されているのに、三角形が描画されないという状況に陥ってしまいました...。

NVIDIA Nsight Graphicsでサンプルプロジェクトと自作レンダラーをキャプチャし比較してみたところ、

自作レンダラーをNsight Graphicsでキャプチャした内容

TLAS作成時に、作成済みのBLAS用バッファに再度セットしていました。

この時点で 2024/9/14 (残り26日) ...

また、以前までの開発はMac環境でWindowsアプリケーション周りの実装に慣れていなかったため、 オフスクリーンレンダリングの対応にも時間を取られました。 提出するレンダラーはEC2の実行環境で実行される際、ウィンドウやダイアログを出してはいけないため、 Windowsアプリケーションのウィンドウを出さずに描画する必要がありました。

今回はReleaseビルドだった場合、ShowWindow関数に渡すnCmdShowの値をSW_HIDEに設定することで対応しました。

#ifdef _DEBUG
        int nCmdShow = SW_SHOWNORMAL;
#else // _DEBUG
        // Release版ではウィンドウを出さない
        int nCmdShow = SW_HIDE;
#endif
        ShowWindow(m_hWnd, nCmdShow);

モデル描画まで

レイトレ合宿8、9とプリミティブなモデルしか描画できなかったので、 techbitoさんの書籍を参考にglTFを用いたモデル描画に対応しました。

※ glTFローダーにはtinygltfを使用しました。

モデルには今年のSIGGRAPHのReal-Time Live!で紹介されていた、Rodinという画像1枚からマテリアルと3Dモデルを生成できる生成AIを用いてglTFデータを作成しました。

Rodinで3Dモデルとマテリアルを生成

www.youtube.com

複数オブジェクト描画のテストとしてBlenderで作成した机もシーンに加え、 ひとまず頂点法線を表示し、imguiを導入しカメラ調整機能を実装しました。

この時点で2024/9/30 (残り9 日)...

いよいよ1週間を切りそうというタイミングでしたが、 この時点ではまだパストレや光源、マテリアル実装が間に合っていませんでした...。

提出作品『Chill in the Box』

残り日数が短かったため、マテリアルはLambert Diffuseと割り切り、表現したいシーンを考えアニメーション実装に時間を割きました。

せっかくglTFを使っているのでアニメーションをBlenderで作成して読み込めるようにしたかったですが、 時間もなかったので、下の画像のような構成のものをハードコーディングしました。

絵コンテのようなもの

パストレ、IBL(Image Based Lighting)、アニメーションの実装が大体出来上がり、 残りの時間で過去の作品では実装できていなかったNEE(Next Event Estimation)の実装に取り掛かりましたが、 なぜかモデルでの反射成分の色味が薄くやや薄暗い感じになっていました。

2024/10/6 (残り3 日)時点での提出物

朝の通勤電車で参考にさせていただいたkiNaNkomotiさんの記事を再度読み直しながら、

GitHub Mobileでコードを見直していると、

NEEの処理で衝突点から光源方向へレイトレースし、光源と接続できた場合に寄与の計算をした後、次の衝突点への移動をせずに終了してしまっていることに気がつきました。

/// 光源サンプリング
/// 光源方向へレイトレースして、光源と接続できた場合
if (!TraceShadowRay(worldPos, lightDir, lightDist, payload.seed))
{
   /// 寄与の計算
   ///トレースを終了←してはだめ
}
else // ← ここのelseが不要だった
{
   /// 方向をサンプリング
   /// throughputの計算
   /// 次の衝突点に移動
}

NEEで光源と接続できた場合、早々にトレースを終了してしまい、 throughputの計算もできていなかったため、反射成分が少なくなってしまっていたのだと思います。

帰宅後すぐさま修正し、無事に最終版を提出しました。

無事に提出!🎉

最終日はスライドをひたすら作っていました。

そして提出した作品がこちらになります。

また、今回のレンダラーについては下記のリポジトリに公開しています。

github.com

レイトレ合宿当日

前回のレイトレ合宿9はお寺で開催され座禅体験や精進料理など非日常を体験できましたが、 今年は今年で初島でリゾート気分な非日常を楽しめました。

月明かりや星空がとても綺麗でした。

お食事も絶品でした

本戦

今年は22個ものレンダラが提出されました。

私が本戦で使用した説明スライドはこちらになります。

毎年ながら他の方の作品は圧倒されるものばかりでした。

Gaussian Splattingを実装されたうしおさんがご自身で小舟に乗りドローンを飛ばして撮影したと聞いた時は驚きました。 すごすぎる...!

本戦の結果としては15位でした。 景品にはWeta Digitalの商用レンダラーMaunkaにちなんで、「たたかうマヌカハニー」を頂きました!

セミナー

セミナーに関しても皆さん幅広い内容の発表をされていて、どれも興味深かったです。

X(Twitter)で話題になっている#つぶやきGLSLを解読する内容についてがむさんが発表されていて、 発表の中で、実際にtwigl.appを開いて解読される様子も見せていただきました。

マジックナンバーを変えた際の変化を見ながら、その部分の記述が何の処理をしているかを推測したり、 パターンを覚えることで解読への足掛かりになるとのことでした。

ベストプレゼンター賞はholeさんでNaNやInfについての発表をされていました。

度々悩まされるNaNですが、 Quite NaNとSignaling NaNという2種類のものに分類されるということを初めて知りました。 また、NaNが絡む演算のコンパイラごとの挙動の違いについても調査されていてとても面白かったです。

私は蛍光現象について15分枠で発表しました。

(今回も蓄光石や蛍光マーカーを忍ばせていました)

レクリエーション

Sponza ジグゾーパズル対決

今年のレクレーションは部屋対抗Sponzaのジグゾーパズル対決でした。

がむさん、Samuelsさん、私のチームは最後の2チームまで残りましたが、惜しくも最後のEvaluationで敗退... 優勝チームにはCornell Boxのジグゾーパズルが贈られました!

レクレーションで使用したパズルはチームの誰かが持って帰って良いとのことだったので、 私たちのチームでは私が頂くことになりました。

なお、現状は...

帰宅後完成されていたYoshi's Dreannさんは7時間かかったそうです....!

Silent NaN の歌のライブ

ジグゾーパズル以外には、holeさんとykozwさんでAI生成されたNaNを称える歌のライブがありました。

サイリウムも配られ、会場は大盛り上がりでした。

とてもいい写真。

まとめ

レイトレ合宿10について振り返りました。

今回はDXRでハードウェアレイトレーシングに入門し、これまでのプリミティブな形状からも脱出できました。 そろそろLambertDiffuseからは卒業して、Specularな材質もレイトレしていきたいです。

毎年刺激が多く、皆さんのレベルの高さに圧倒されるばかりです。 私もできることを一つ一つ増やしていきたいです。

運営の皆さん、参加者の皆さんありがとうございました!

2023→2024

はじめに

はやいもので2023年ももうすぐ終わりますね。

今回はXの投稿を遡りながら2023年を振り返り、2024年の目標を書いていきたいと思います。

2023年振り返り

東京ゲームダンジョン

2023年は「東京ゲームダンジョン2」から始りました。

Unity1Weekの「NOA's Project」をきっかけに始まったSteam版「NOA's PROJECT」の開発も3年目に突入しました。 今年は「東京ゲームダンジョン2」で初出展し、「東京ゲームダンジョン3」にも出展しました。

来てくれた方が実際に手に取って遊んでいる様子を見たり、 ゲームへのフィードバックをいただけてとても貴重な経験になりました。

年明けの「東京ゲームダンジョン4」にも2日出展デカ枠で出展します。 前回販売できなかったチルガイアクリルストラップも販売予定です。 1/20(土)、1/21(日) 都立産業貿易センター浜松町館5階 ブースA-3にてお待ちしております!

東京ゲームダンジョン 4 ► 2024年1月20日(土)・21日(日)東京・浜松町でインディゲーム展示会を開催!

Unity1Week

今年Unity1Weekには4月に1度だけ参加し、 ハムスターたちのラップバトルを体験する 「HAMSTAR MC BATTLE」を制作しました。

https://unityroom.com/games/hamstar

ちょうど妹が就活で関東に来ていたタイミングで自宅に泊まっていたのでキャラ絵やラップ、声入れを手伝ってもらいました。 妻(NaTsu Beats)にもビート制作や声入れを手伝ってもらいました。

Thanks guys 😉

ビートチェックや勝敗判定の演出など、 好きなラップバトルの要素を盛り込み 個人的にもかなり満足のいくものが作れました。

引越し

4月には都内を離れ、自然豊かな街に引越しました。

空気が美味しいのと星が見えるところ、いろんな仲間たち🦢🐟🐢に出会えるところが気に入っています。

台湾

5月には妻の実家の台湾に4年ぶりに行きました。

今年から毎年行きたいです。 (イッヌかわよ)

SIGGRAPH

8月には憧れの舞台であったSIGGRAPH視察にも行きました。

スパイダーバースのリファレンスは大事だよというお話がとても刺さりました。 "Cinematography For Stylized Motion Pictures"

Ray Tracing in One WeekendのBird of a Feather でPeter Shirley氏ともお話しできて嬉しかったです。

LAにいる父のお店にも行きました。

https://sushikatsuya.com/pages/7.php

WebGPU

今年のレイトレ合宿ではWebGPUでGPUレンダリングに挑戦しました。

Élie Michel氏のWebGPU C++ Guideをベースに進め、 コンピュートシェーダーでのレイトレを実装しました。

speakerdeck.com speakerdeck.com

大変な部分も多かったですが、作品提出までできてよかったです。

kugi日記

2021年に上京して描き始めた日常4コマ漫画の「kugi日記」も3年目に突入しました。

note.com

  • 1年目(2021年):58話
  • 2年目(2022年):15話
  • 3年目(2023年):7話

と年々更新頻度は減っていますが、「描きたい時に楽しんで描く」をモットーに今後もゆるりと続けていきたいと思います。

1コマ of 2023

ライミング

今年でクライミングを始めて10年だったようです。 高校の部活を引退し、大学、社会人と場所を変えいろんな場所で登ってきましたが、 近くにジムがなかったり、登れても月に1度だったりとなかなか高校時代のようなモチベーションでなかなか登れていませんでした。

引越しもあり近所に良いジムを見つけ、10月ごろからようやく週2で登りに行けています。 久しぶりにガッツリ登ることが習慣づいてきて、ただひたすらに壁と向き合うことの楽しさを改めて実感しています。

来年はコンペや外岩にもどんどん行きたいです。

2024年の目標

2024年の目標としては以下を掲げます。

憧れをもっと身近に

今年は憧れであったSIGGRAPHの舞台や、グラフィックスの業務も始まり、学生の頃に抱いていた憧れの環境に身を置くことができたと思います。 来年は更にそのような憧れを憧れにとどめることなく、身近なものにできるように挑戦していきたいです。

まとめ

今年も多くの方々に大変お世話になりました。

来年も引き続き keep chilling の精神で精進していきます。

LET'S GO 2024 !!!

猫目石のレンダリング - Chatoyancy -

はじめに

こちらの記事は レイトレ合宿9アドベントカレンダー9週目の記事です。

今回は宝石のレンダリング、その中でも猫目石(キャッツアイ)、タイガーアイなどで見られる光学現象について紹介します。

猫目石

猫目石は宝石の一種でキャッツアイとも呼ばれています。 その名の通り、光の反射によって現れる猫の目のような模様が特徴的です。

また、パワーストーンであるタイガーアイでも同様の模様を観測できます。

猫目石 - Wikipedia

タイガーアイとは|鉱物データ・特徴・意味・効果・石言葉 - ヒカリカンパニー公式WEBショップ

数年前にふらっと旅先で寄ったアクセセリーショップで猫目石タイガーアイを購入しました。 実際にはもっと高価なはずなので、厳密には猫目石ではないと思います。

ただ今回は便宜上、猫目石と呼ばせてください。

猫目石(左)とタイガーアイ(右)

猫目石の方は綺麗な線の模様が、タイガーアイの方も直線ではないですが光の筋のような模様が現れています。

Chatoyancy(シャトヤンシー効果)

猫目石などでみられる模様は Chatoyancy (シャトヤンシー効果) と呼ばれています。

では、シャトヤンシー効果はどのように現れるでしょうか?

調べていると、"Rendering gems with aterism or chatoyancy" 1 という論文に辿り着きました。

論文ではシャトヤンシー効果は猫目石の以下の2つの特性によるものと書かれています。

Inclusion (インクルージョン)とは鉱物が形成される過程で内部に取り込まれた、空気、水分、他の微小結晶などの内包物です。

インクルージョン (鉱物) - Wikipedia

また、Cabochon Cut (カボション・カット) とは宝石のカット法の一種で、 ダイヤモンドなどでみられるファセット・カットと異なり、曲面になるように研磨加工するものです。

カボション・カット - Wikipedia

猫目石の構造の概略

実際に猫目石を天井のシーリングライトに向けてかざしならが見てみると内部のインクルージョンを観測することができました。

猫目石を透かして観測できたインクルージョン

斑点模様のように見えているのが筒状のインクルージョンを軸方向に見たものです。 一定の間隔をあけて筒状のインクルージョンが平行に並んでいることがわかります。

シャトヤンシー効果の原理

シャトヤンシー効果の原理は以下のようになっています。

  1. 入射光が鉱石の表面で屈折し内部に進む
  2. 屈折光がインクルージョンで反射する
  3. 反射した光が鉱石の表面で再度屈折し外部に出る
  4. 3.で出射した光が最終的に集まり、光の筋として表面に現れる

光がインクルージョンで反射する様子

照明環境を変えて撮影した様子

照明環境を変えて撮影

猫目石タイガーアイに対して異なる照明環境下で撮影を行ってみました。

まず1枚目をよく見ると猫目石の方には模様が2つ出ているように見えます。 また、2枚目のiPhoneのバックライトのみの方ではタイガーアイに模様が出ていません。

そして、1枚目の模様は2枚目と3枚目の模様が合成されているように見えます。

照明環境を変えてみることで実際にインクルージョンと照らされる方向によってシャトヤンシー効果の違いが現れることがわかりました。

また、私の持っているタイガーアイの模様が真っ直ぐではないのも内部のインクルージョンの並びが均一でないからかもしれません。

猫目石レンダリング

それでは猫目石レンダリングについてみていきます。

インクルージョンのモデル化

Yokoiら1の手法ではインクルージョン表面のマイクロファセット(微小平面)のほとんどがインクルージョンの軸方向 Zに対して直交する方向に分布していると仮定し以下のようにモデル化しています。

インクルージョンにおけるマイクロファセットの方向

  •  Z: インクルージョンの軸方向
  •  \psi(S): 方向  S に分布するマイクロファセットの割合
  •  \phi: 方向  Z と 方向  S のなす角
  •  \theta:  \frac{\pi}{2} - \phi
  •  n: ラフネス

方向  S に分布するマイクロファセットの割合  \psi(S) については、 以下のように  cos^{n}\theta に比例するとしています。 ( aについては言及がありませんでしたが、インクルージョンの半径ととらえました)

 \displaystyle
\psi(S) = a cos^{n}\theta

内部の微小ボリュームにおける散乱

次に鉱石の内部に任意の方向に並んだインクルージョンが分布していいる微小ボリュームがあると考えます。

内部の微小ボリューム

  •  V: 視線方向
  •  V': 点  Q で屈折される以前の方向
  •  L: 光の入射方向
  •  L': 入射光の屈折方向
  •  H:  V' L'のハーフベクトル

微小ボリューム内のインクルージョンによって散乱された光は V'方向に進みます。 この散乱光は屈折を考慮した光の入射方向 L', 屈折以前の視線方向 V'のハーフベクトルの方向に分布するマイクロファセットの割合 \psi(H)に依存するとしています。

シャトヤンシー効果のモデル化

上記を踏まえ、シャトヤンシー効果は以下のようにモデル化されます。

 \displaystyle
T = rR + (1 - r) F e^{-c l_o} + I'
 \displaystyle
I' = \int_L (1 - r)(1 - r')I k\psi(H) e^{-c(g(l) + l)}dl
  •  T: 視線方向への出射光
  •  r: 点  Q における反射係数
  •  R: 点  Q における入射光
  •  F: 点  U における入射光
  •  c: インクルージョンでの散乱を考慮した鉱石内部の吸収係数
  •  I': インクルージョンでの散乱光
  •  1 - r': 点  Q' における透過係数
  •  k: インクルージョン内に分布するマイクロファセットの反射係数
  •  \psi(H): ハーフベクトル H方向に分布するマイクロファセットの割合

光源から視点までの経路

 T の第1項 rRは点 Qにおける反射光、 第2項 (1 - r) F e^{-c l_o}は減衰を考慮した経路 UQ間の透過光です。 これらに対し、インクルージョンでの散乱光  I' を加算しています。

 I'は経路UQ間に存在する微小ボリューム内で散乱した光について積分を行なっています。

Yokoiら1の手法では、 I'積分計算のために事前計算されたRay Distribution Map(レイ分布マップ)を用いています。

レイ分布マップは鉱石内に入射するレイを光源から一定の間隔でサンプルして飛ばし、鉱石と交差した点 Q'、屈折方向 L'、レイの透過係数 1-r'を保存します。 なお、2回目以降の屈折に関しては影響が小さいため無視されています。

まとめ

今回は猫目石でみられる光学現象であるシャトヤンシー効果(Chatoyancy)について、Yokoiら1の手法を参考に学びました。

今回は触れませんでしたが、論文のタイトルにもある Asterism(スター効果) も原理としてはシャトヤンシー効果と一緒のようでした。 インクルージョンが綺麗に3方向に入っていると、星のような模様が現れるようです。

何気なく購入した石の構造やそれに伴う光学現象について学べてとても面白かったです。

実際に実装までは至りませんでしたが、また空いた時間で描画までできたらなと思います。

また、猫目石以外の鉱石についての論文2やスライド資料3も見つけたのでそちらにも目を通したいです。

(スライド資料3に関してはエストニアにあるタルトゥ大学で行われているグラフィックスに関するセミナーの資料のようでした。)

2022→2023

はじめに

あけましておめでとうございます!

今回は2022年の振り返り、そして2023年の目標について書いていこうと思います。

2022年振り返り

Unity1Week

Unity1Weekには3回参加しましました。

正座ネコ

「正座ネコ」はお題「2」のときの「Kani と Uni」に続き、手書きアセットで作ったゲームです。

(「Kani と Uni」については以下の振り返り記事でまとめています。) kugi-masa.hatenablog.com

提出したのははお題「正」の評価期間中でした。 年末実家で「正座したネコが出荷されるように流れてくる」絵が思い浮かび、年明け後急いで作って提出した覚えがあります。

前作でのフィーバータイムに味を占め、「正座ネコ」では生ボイスをゲームに取り入れました。

Time.deltaTimeを掛け忘れるという初歩的なミスで環境によってはピーキーな挙動になってしまうなど、相変わらずな感じでしたが、 kugi ワールドを全面に出せた作品になりました。

Fxxxin Fashion Club

お題「そろえる」ではノアプロでいつもお世話になっている nattuhanさん、つっちーさんに加え、ジュンさんと妻のNaTsuの5人チームで「Fxxxin Fashion Club」を作りました。

他のメンバーの振り返り記事も合わせてご参照ください。

制作期間としては10日間で遅刻にはなってしまいましたが、モデルやBGMのリソースはほぼ全て自作で、4人対戦のオンラインゲームを満足のいくクオリティで最後まで作り切ることができました。 ちょうどゴールデンウィークで延長戦も含め、これまでのUnity1Weekと比にならないほど全力で走り抜けた期間でした。

何よりテストプレイの段階からみなさんとわちゃわちゃしながら限界開発テンションで盛り上がれてめちゃくちゃ楽しかったです!

個人的には反省も多かった作品で、実装の優先度を見誤った結果、ゲームループ作成までに時間がかかり、 終盤つっちーさんにかなり頼りきってしまいました。

KPTでの個人振り返り

Unity Cloud Buildの学生ライセンスが切れていたこともあり、GameCIを用いてビルドを行いGitHubPagesへデプロイするというテストプレイ環境の構築を1week開始前から挑戦していました。

参考にさせていただいた記事:GameCI で Unity の CI 環境を GitHub Actions で構築する

しかし、本番運用までは至らず(PUN2を使う場合は別途ビルド設定が必要だった...??)、潔く切り捨てるのではなく半日調査してしまったことも皺寄せとして終盤に影響が出てしまいました。

1週間という短い期間での開発だからこそ、短いスパンで状況を整理して、優先度の確認を行うべきだと改めて感じました。

Glow in the Dark

お題「ためる」では「Glow in the Dark」というゲームを作りました。

「ためる」でもサウンド制作は妻にお願いしました。

青木ととさん主催の「unity1week online共有会 #9」にも参加し、制作の過程やこだわったポイントについてお話しさせていただきました。

www.youtube.com

今作はライティングや発光の表現にこだわった作品で、ライトマップとライトプローブのベイクなどにも挑戦しました。 過去の作品「密蜂 ~Cluster Bee~」でもライティングに挑戦したことはあったのですが、 当時は参考動画や記事のパラメータを見様見真似で設定しライトベイクしていました。 今回は少し工夫してベイクできたので学生だった当時と比べて少しは成長したと実感できました。

また当時も共有会に参加していて、今回の資料作成の合間に久しぶりに自分の発表を見ていたのですが、 スライドの作り方が今と違っていたり、まだヒトの姿をしていたりと懐かしかったです。

📣 unity1week online共有会 #1 - YouTube

その他

ランキングライブラリの作成

naichiさんのランキングライブラリを参考に、UIやデータの送信タイミングを指定できるテンプレートライブラリを作成しました。

github.com

まだまだ改良の余地ありなので、空いた時間などでIssueを消化していきたいです。

売り子のお手伝い

Unity1Weekというより、Unityゲーム開発者ギルド関連ですが、IGC2022で売り子としてむじさんのお手伝いをしました。

同人イベントの出展側の様子を体験することができ、とても貴重な経験になりました!

NOA's PROJECT

Unity1Weekの「NOA's Project」がきっかけで始まったnattuhanさん、つっちーさんとの Steam版「NOA's PROJECT」の開発は、だいたい月曜日の夜に集まってゆるゆる開発するスタイルで進めました。

Unity1Weekや他のイベントへの参加などで2022年は小休止する期間もありましたが、私はスキルの量産や細々とした実装に着手しました。 前年に続き、ボクセルモデル制作にも挑戦しました。

Unity1Weekを含めですが、2022年もチームメンバーのnattuhanさん、つっちーさんにはお世話になりっぱなしでした。 開発以外でも何度か飲みにも行けてよかったです。

2023年ではまず1月15日にある東京ゲームダンジョン2の出展頑張りたいと思います!

ISUCON

2年ぶりにISUCONにも参加しました。

kugi-masa.hatenablog.com

結果としては予選敗退でしたが、会社の同期と一緒に勉強できて楽しかったです。

また、AWSインスタンス上での作業は初めてだったのですが、後述のレイトレ合宿の本番環境実行の予習になったのでよかったです。

レイトレ合宿

2022年は学生の頃からいつかは参加してみたいと思っていた「レイトレ合宿」に参加しました。

詳しくはレポート記事をご参照ください。

kugi-masa.hatenablog.com

レンダラーの実装を通して研究内容のスペクトラルレンダリングや蛍光周りの復習ができました。 実際の合宿でもセミナーや参加者の皆さんの作品などを通してとても刺激を受けました。

2023年も機会があればまた挑戦したいです!

自作キーボード

振り返っていて驚いたのですが、2022年は小さいものも含め4つ自作キーボードを作っていました。

自宅用のキーボードとして使用しているLily58はかなり使い心地がいいです。 スイッチソケット付きなのでいろんなスイッチを試してみたくなります。

(自作ケーブルキットを買ったまま積んでいるので作らなくては...)

kugi日記

上京してきてから始めた日常4コマ漫画の「kugi日記」は74話になりました。

note.com

2022年で書いた話は16話で前年と比べるとペースは落ちてしまいましたが、 毎月1話の目標は達成できました!

日常にあった出来事の話なのでどうしても投稿するタイミングと描かれている内容に時差があるのですが、 2023年はできればこの時差を縮めていきたいと思いつつも、 引き続きゆる〜〜く描いていけたらなと思っています。

1コマ of 2022

NaTsu Beats

今年から妻が「NaTsu Beats」というアカウントで楽曲制作を始めました。

私もMV制作などでサポートしました。

kugi-masa.hatenablog.com

妻のnoteで楽曲制作を始め出した頃のことを

当初はちょうどチル系の音楽にハマり出した頃でもあり、

と書いているのですが、これはノアプロのDiscordで作業中にnattuhanさんがNujabesやチルいBGM集を流していたことで私がどハマりして、 自宅でも流していたことが影響しています。

note.com

そんな中、前述の通り妻は「Fxxxin Fasion Club」でサウンドを担当することになったので、 人生の流れはまわりまわって繋がっているんだな〜と振り返っていて感じました。

ライミング

2022年後半はあまりいけませんでしたが、退勤後に同期と登りにもいきました。

#退勤クライム でその様子がのぞけます。

twitter.com

2023年の目標

2023年の目標としては以下を挙げたいと思います。

  • グラフィック技術の習得と深堀
  • NaTsu Beatsのサポート
  • 登りに行く頻度を上げる

2022年12月ごろから本業の方でもグラフィックス周りのことをすることになりました。 2023年では技術の習得とさらに知見の深掘りに重点を置いて取り組んでいきたいです。

また妻は2023年でNaTsu Beatsでの活動の幅をさらに広げたいそうなので、私もしっかりサポートしていきたいです。

ライミングに関しても目標を掲げました。 最近本当に運動不足で筋力がどんどん落ちているので、心身ともに健康を維持したいです。

「何事にも挑戦」、「バランスの良いインプットとアウトプット」は人生を通しての目標なので引き続き頑張っていきたいと思います!

まとめ

2021→2022での振り返りができなかったので久しぶりの振り返りになりました。

久しぶりに2020年振り返りも見返していたのですが、 こうして記録に残しているといろいろ思い出せるので良いですね。 実際に書き起こしてみると、2022年もいろんなことに挑戦できた1年でした。

2023年も頑張っていきたいと思います! それでは!

UnityのTimelineを使ってMV製作した話

はじめに

こちらの記事はUnityゲーム開発者ギルド Advent Calendar 2022の11日目の記事です。

adventar.org

今回はUnityのTimelineを用いてMV制作を行った話について書こうと思います。

NaTsu Beats

今年の1月ごろから妻が趣味で楽曲制作を始めました。

www.youtube.com

是非チャンネル登録をお願いします!!

制作を始めたきっかけについては妻のnoteをご覧ください。

ビートメイキングを始めた話|NaTsu Beats|note

妻はイラストを描くことも好きなので、イメージイラストやちょっとしたアニメーションも作成してYouTubeにアップロードしています。

私はMV制作のお手伝いをしていて、 先日公開された "A Brand New Day!" という楽曲ではUnityのTimelineを用いて作成しました。


www.youtube.com

TimelineでのMV制作

MV制作をTimelineでしよう!となった理由は単純にTimelineの勉強がしたかったからです笑

バージョンは以下のものを使用しました。

基本的に絵素材は妻が作成し、実装を私が担当しました。

動画の出力にはUnity Recorderを使用しました。

ソースコードについては以下のリポジトリに公開しています。

github.com

全体の流れ

MVの流れとしては、NA-CHANとアザ...セイウチのCHILL-BALLが1日かけて街や公園、森を巡るものになっています。

NA-CHANとCHILL-BALL

曲は既に出来上がった状態でのMV制作だったため、 どのタイミングで何を出すかといった指示メモを書いてもらいました。

指示メモ

場面の転換

今回場面としては大きく分けて4つありました。

4つの場面

NA-CHANとCHILL-BALLが歩くアニメーションを再生しながら、 背景スクロールで場面転換を表現しました。

背景スクロールについて

背景用のSpriteRendererを持ったGameObjectを2つ用意して、 スクロールさせつつ、前後を入れ替えることで実装しています。

スプライトのスクロール

スクロール処理はBackgroundMoverが処理しています。 LoopTimeで指定した時間でTransferDistだけ進み、後方の位置へ戻ります。

ロケット鉛筆の要領ですね!

FrontとBackを交互に入れ替える

背景スクロール用のTimeline拡張

Timelineウィンドウでシークバーをスクラブした場合にも再生中と同様に背景スクロールさせたかったため、拡張機能を実装しました。

今回のMV制作では曲の進行に合わせて場面を切り替えたり、スクロールを止める場面があったため、各クリップでの細かいタイミング調整が必要でした。 スクラブでの確認ができないと編集を行うたびに先頭から再生することになるので地獄を見るところでした…

Timelineウィンドウ上でスクラブしてもスクロールが反映されるように拡張

tips.hecomi.com

こちらの記事を参考に以下のTimeline拡張を行いました。

ドキュメントによると

PlayableBehaviourのProcessFrame()はPlayableGraphのProcessFrameフェーズで実行されるメソッド

のようです。

参照:Unity - Scripting API: Playables.PlayableBehaviour.ProcessFrame

これは再生時だけでなく、Timelineを再生していないEditorモードでも実行されるとのことでした。つまり、シークバーをスクラブする際にも実行されるようです。

参照:How to get Playable.GetTime() when not in play mode ? - Unity Forum

BackgroundTimelineBehaviour.ProcessFrame

BackgroundTimelineBehaviourではProcessFrame()内で背景スクロールの処理であるBackgroundMover.ScrollOnFixedFrameRate()を実行しています。

背景スクロール処理
BackgroundMover.ScrollOnFixedFrameRate()

信号の場面などで背景スクロールを停止している部分ではIsStopフラグがtrueになったクリップを割り当てています。

BackgroundMoverの処理を呼ぶBackgroundTimelineBehaviour

Timeline再生時のスクロール

Timeline再生中はMonoBehaviourUpdate()で呼び出すときのように、FrameData.deltaTimeを元にスクロール位置を計算しています。

Timeline停止時のスクロール

Editor上でスクラブをするようなTimelineが再生されていない状態ではFrameData.deltaTime0.0fになるため、そのままFrameData.deltaTimeは使用できませんでした。

Timeline停止中はProcessFrame()内で取得したクリップにおける再生位置(フレーム)を元にスクロール位置を計算しています。 また、BackgroundTimelineClipに現在のクリップまでにスクロールさせた分の経過時間(フレーム)を持たせることで、 スクロール停止クリップを挟んだ場合にも対応させています。

クリップが直前までの経過スクロール時間を保持している

背景スプライトの切り替え

スクラブで背景がスクロールできるようになったので、 次は各場面でスプライトを切り替えるための拡張を作成しました。

  • BackgroundSceneTrackSpriteRenderをバインドするスプライト切り替え用の拡張トラック
  • BackgroundSceneClip:切り替えるスプライトを指定する拡張クリップ
  • BackgroundSceneBehaviour:バインドしたSpriteRenderにクリップで指定したスプライトを割り当てるPlayableBehaviour派生クラス

スプライトの切り替え用の拡張

FrontとBack用のBackgroundSceneTrackを用意し、BackgroundSceneClipで指定したスプライトを各SpriteRendererに割り当てています。

FrontとBackの境目が画面に映らないようにフレーム送りでの細かい調整を行なったため、スクロール拡張がかなり役立ちました。

フレーム送りで境目が気にならないように調整

また制作序盤ではMarkerを使って通知を送ってシーンの切り替えを行おうとしていました。 しかし、スクラブなどを考慮するとトラックにしてしまった方が良いと思い、最終的には拡張トラックを作成しました。

今回は使用しませんでしたが、SceneSetNotificationはその名残です。

マーカー実装時には以下を参考にしました。

クリップ上にkani-chanが...!!

地面のつながりを表現するシェーダー

地面の表現としては上段・中段・下段用のスプライトを用意し、スクロールさせずにシェーダーで実装しました。

素材がドット絵風なテイストだったので、2色のグラデーションに対してポスタライズ処理を使ったシェーダーをShaderGraphで作成しました。

水平方向の2色グラデーションに対してポスタライズ処理をかけたシェーダー
Gradient.shadergraph

パラメーターは以下の通りです。

  • ColorRight:右端の色
  • ColorLeft:左端の色
  • T:ポスタライズ処理領域の中心 [0→1]
  • Width:ポスタライズ処理領域の幅
  • PosterizePower:ポスタライズ処理の度合い

このシェーダーを各スプライトに割り当て、背景スクロールに合わせてTを変化させるトラックを作成しました。

色情報を割り当てるための拡張

  • GroundColor:上中下段のマテリアルに対して色情報をセットするクラス
  • BackgroundColorTrackGroundColorClipChangeColorClip(後述)用の拡張トラック
  • GroundColorClip:地面用のスプライトにセットする色の指定やTを変化させる拡張クリップ
  • BackgroundColorBehaviour:地面の色の変更処理や空フィルターの色を変更する(後述)ためのPlayableBehaviour派生クラス

GroundColorClipで指定する色情報はGradientとして持たせていますが、内部的にはGradient.Evaluate()で取得した左端(time = 0)と右端(time = 1)の色のみを使用しています。

Tの変化に関してはBackgroundColorBehaviour.ProcessFrame内で以下のように計算してそのまま渡すことができました。

クリップの開始→終了を0→1とする

背景スクロールに合わせて地面シェーダーを変化させる

曲のリズムに合わせたキャラクター、小物の動き

MVなので途中に出てくるキャラクターや小物の動きを曲に合わせる点についてもこだわりました。 是非キャラクターたちの動きにも注目してみてください!

おすすめシーン

時間変化に合わせた空と色調補正について

ここでは1日の時間に合わせて情景の変化をさせるために、 空の色や色調補正をかけるための拡張クリップを作成しました。

  • ChangeColorClipTypeに応じて空の色変化や色調補正を行う拡張クリップ

TypeとしてはSKYCOLOR_ADDITIVESPRITE_ALPHAの3種類作成しました。

3種類のChangeColorClip

空の表現について

空については時間変化に応じて カメラのbackgroundColorプロパティを変更しグラデーションさせています。

ChangeColorClipのType.SKYでグラデーションを指定

地面シェーダーで使用したクリップ長を1としたときのクリップ位置tもここでも使用しました。

クリップの再生に合わせてグラデーションさせるために、 ChangeColorClipで設定されたGradientに対してGradient.Evaluate()Colorを取得する際のtとして渡しています。

色調補正について

ある程度MVの流れができ、最終的に色調補正をかけたくなりました。

はじめはURPのPost-processingに含まれるColorAdjustmentsを使用しようと思い、設定を進めていました。

URPのポストプロセス機能

しかし、ポストプロセス(Post-processing)の名前の通り、背景色が描画された後でしか適用できず、背景色を色調補正から除外することはできませんでした。

背景を含めない補正と含まれる補正
せっかく設定した空の色が変わってしまう

空(背景)の色については先程のグラデーション機能で色を決めているため、

「空(背景色)以外の描画結果に対して、Timeline経由で色調補正をかける」

がここで目指すべきゴールでした。

ただ、全てのスプライトを拡張トラックなどで指定して調整するのは途方もない作業かつ、スプライトが増えた場合への拡張性がありません。

最終的にRenderTextureを使った方法を採用することにしました。

カメラを2つ用意する

スプライトの描画結果をRenderTextureに出力するRenderTextureCameraを用意し、MainCameraで出力されたRenderTextureと背景色を描画します。

空の色の調整と色調補正のフロー

色調補正ではChangeColorClipType.COLOR_ADDITVEを使用して時間変化に合わせて、クリップで指定されたグラデーションを用いてRawImagecolorプロパティにセットしています。

まとめ

MVを作る上でこうしたい!という表現がたくさん出てきてそれに合わせる形でいろんな機能拡張に挑戦しました。

最終的に録画を行ったTimelineウィンドウ

初めてのTimeline拡張で冗長なことをしている部分も多々あったとは思いますが、 最終的に満足のいくMVを公開することができました。

また、かなり参考にさせていただいたTimeline拡張の記事を執筆されている凹みさんも先日Unityを用いてムービー作成をされた際の記事を公開されています。 (Happy Wedding!!🎉)

tips.hecomi.com

"A Brand New Day"のMV作成後、そこまで動きの多くないMV(Good Old Times / relaxing lofi beat - YouTube)をAffter Effectsで作ってみました。 他の方法でのMV作成も試してみて、凹みさんも書かれているように、サクッと簡単な動画を作るのであれば動画編集ソフトがやはり使いやすいなと感じました。

ただ、無い機能を自分で拡張して作ること自体は学びが多く、 いろんな小さな課題に対して解決策を考えていく過程はとても楽しい時間でした! チャレンジした分だけ得られるものはあったと感じています。

今回は"A Brand New Day"のMVのためのTimeline拡張の話だったので、限定的なものも多いかとは思いますが、 この記事がまたTimeline拡張へ挑戦する方の一助となれば幸いです。

それでは!

レイトレ合宿8参加レポート

はじめに

9月2日(金)から9月4日(日)に沖縄本島で開催されたレイトレ合宿8に参加してきました! 今回はレイトレ合宿までの準備と当日の振り返り記事になります。

レイトレ合宿に参加するまで

今回の目標

まずは参加が決まってから今回の目標を決めました。

  • Ray Tracing in One Weekendシリーズをベースに進める
  • 蛍光現象のレンダリング

学生の頃 Ray Tracing in One Weekendでレイトレ入門したため、 今回は残りの2部作をベースに進めました。

"Ray Tracing in One Weekend"(1週間レイトレ)をやってみた - kugi's notebook

またアドベントカレンダーで書いた蛍光現象を実際にレンダリングするところも目標としました。

蛍光現象のレンダリング - kugi's notebook

制作の過程

制作までの記録をメモ書き程度ですがNotionに残して進捗管理していました。

Notionで制作までの過程を記録

sprinkle-relative-0fd.notion.site (sppがppsになっていて恥ずかしい...)

レイトレ合宿のポータルページには提出までの残り時間が表示されているのですが、 自分の記録にも記載してモチベーション維持に役立てました。

締め切り駆動開発...!!

残り時間表記

レイトレ合宿

私は2日目の9月3日(土)から参加しました。 開催日前日ごろから台風が沖縄に接近していて当日飛行機が飛ぶかわからない状況でしたが、無事現地に到着することができました。 あいにくの天気ではありましたが、沖縄の料理や泊まったホテルは素晴らしかったです!

合宿では「本選」の他に「全日本レイトレ選手権 デノイズ部門」や「セミナー」が開催されました。

私は本選に参加し、セミナーでは自己紹介LTを行いました。

本戦

本戦では

フレームレートは10fpsから60fps、長さは3秒以上10秒以下のアニメーションを10分以内にレンダリングする

というレギュレーションのもと提出した作品をAWSインスタンス上で実行し、参加者全員で互いの作品を10点満点で評価します。

私はFluorSwitchという作品を提出しました。結果としては79ptで16人中13位でした。

蛍光塗料が塗られたボールが転がり、左の壁にあるスイッチを押すことで照明がUVライトに変わり、蛍光現象により緑色に発光するという作品です。

蛍光の表現にはアドカレでも記載したYamamotoらのモデルを用いました。

10分の制限時間の中でどうリソースを使うか試行錯誤して、前半はRGBレンダリング、後半はスペクトラルレンダリングに分けたり、sppを調整したりしましたが、 やはりノイズの残る結果となってしまいました。

ただ、当初立てていた目標は概ね達成することができました。 他の参加者の作品ではOptiXやOIDNを用いてデノイズされていたので、次回はデノイズにも挑戦したいです!

景品としていただいた三角プリズム

まとめ

今回はレイトレ合宿8について振り返りました。

学びの多い合宿でレイトレをされている方との繋がりができました! 運営の皆さん、参加者の皆さんありがとうございました!

そして何より、自作のレンダラー制作に挑戦できて本当に良かったです。 これからも継続して勉強していきたいと思います!

蛍光現象のレンダリング

はじめに

こちらの記事は レイトレ合宿8アドベントカレンダー8週目の記事です。

今回は蛍光現象とそのレンダリング手法について書きたいと思います。

蛍光現象

みなさんは蛍光現象をご存知でしょうか? 遊園地の入場チェックで手にスタンプをされたことのある方やブラックライトで照らすことで浮かび上がるアートなどを見たことがある方もいらっしゃるかもしれません。

蛍光現象とは、蛍光分子がある特定の波長の光を吸収して、その吸収したエネルギーによって別の波長の光を放出する現象のことです。

例えばこちらのTRICKマーカーの水性インクにも蛍光分子が含まれています。

先日購入したTRICKマーカー

それぞれのインクの蛍光分子が、UV LEDの光(紫外線)を吸収して、赤、緑、青と異なる波長の光を放ちます。

室内照明環境下だと見えないが、
ブラックライトを照射すると文字が浮かび上がってくる

蛍光分子にはこのように、吸収する光の波長領域を表す励起スペクトル(Excitaion Spectrum)と放出する光の波長領域を表す蛍光スペクトル(Emission Spectrum)を持ちます。

点線:励起スペクトル、実線:蛍光スペクトル

グラフは蛍光顕微鏡などで用いられる蛍光色素であるAlexa Fluor®抗体の蛍光特性です。

蛍光スペクトルビューアーを使うと選択した蛍光色素の励起スペクトル、蛍光スペクトルを確認でき、励起光を指定して蛍光現象のシミュレーションをグラフ上で行うことができるのでおすすめです。

蛍光現象のさらに詳しい説明は下記を参照してください。

蛍光の基本原理 | Thermo Fisher Scientific - JP

その他の蛍光の例

実は蛍光現象は身近なところにも応用されています。 紫外線を吸収して青白い光を発光させてより服の白さを目立たせるため、洗剤などに使われているようです。

花王 | 製品Q&A | 【成分・働き】蛍光増白剤とは?

また、医学の分野では蛍光色素で細胞を染色して観察する蛍光顕微鏡なども使われています。

蛍光現象と蓄光の違い

蛍光現象と似たものとして、蓄光があります。

フォトルミネセンス(Photoluminescence)という括りでは、蓄光も光を吸収し、そのエネルギーによって光を再放出する過程です。 蓄光の場合は発光の寿命が長く、物質への光照射をやめてからも発光し続けます。

詳しい違いとしては光を吸収した蛍光分子の励起状態が異なるようです。

ヤブロンスキー図
Wikipedia より引用

蛍光 - Wikipedia

ちょうど先日立ち寄った100円ショップに蓄光材質のものが売っていたので買ってみました。

蓄光材質
室内照明で照らしている状態から、照明を消すと発光する

冒頭のTRICKマーカーによる蛍光の場合は暗所でUV LEDライトを用いて照らしていましたが、今回の場合は何も照らしていない状態で発光し続けています。

また、iPhoneのLEDライトで照らした場合とUV LEDライトで照らした場合で比較してみたところUV LEDの方が明るく発光しました。 購入した蓄光素材の詳細な励起特性についてはわかりませんが、より短波長領域の光を吸収するようでした。

蛍光現象の2つの特性

蛍光現象には以下の2つの特性があります。

  • 出射スペクトルと蛍光スペクトルの関係
  • トークスの法則

出射スペクトルと蛍光スペクトルの関係

出射スペクトルは蛍光として放出される光の各波長での強度を表したものです。

また、蛍光分子が蛍光特性として持つ蛍光スペクトルは励起スペクトルにおけるピークでの波長を励起光(吸収する光)とした時の出射スペクトルです。下図の場合、励起光1がピークでの励起光になります。

蛍光スペクトルと出射スペクトル

図のように、異なる波長の励起光が蛍光分子に与えられたとしても、放出される出射スペクトルは蛍光スペクトルの相似形になるという特性があります。

トークスの法則

トークスの法則

トークスの法則は蛍光として放出される光のエネルギーは、吸収されるエネルギーよりも低く、励起光の波長より長波長領域の光になるという法則です。

図の蛍光分子の場合、紫外線(UV LEDライトの光)を吸収して、可視光領域の光が放出されます。UV LEDライトで照らしてヒトの目によって観測できるようになるのはこのためです。

蛍光現象のレンダリング

さて、前置きが長くなってしまいましたが、 ここからは蛍光現象のレンダリング手法について紹介します。

スペクトラルレンダリング

特性からもわかるように、蛍光現象は光の波長に依存した光学現象です。波長依存性の高い光学現象をレンダリングするためには、一般的なRGBレンダリングではなく、波長ごとの値を考慮したスペクトラルレンダリングが必要です。

スペクトラルレンダリングとRGBレンダリング

RGBレンダリングではあらかじめ現実の光のスペクトルを等色関数を用いてRGBに変換し、そのRGBを用いて照明計算を行います。 それに対し、スペクトラルレンダリングでは光のスペクトルからサンプリングされた値を用いて照明計算を行った結果をRGBに変換するため、物理的に正しい光のシミュレーションを行うことができます。

スペクトラルレンダリングについては、shockerさんのページやPenguinさんのレイトレアドベントカレンダー2021の記事がとても参考になります。

スペクトラルレンダリング - Computer Graphics - memoRANDOM

スペクトルレンダリング - Qiita

多重重点的サンプリングを用いた手法

Yamamotoらの手法では、蛍光現象の2つの特性に基づいて、スペクトル強度 I_i(\lambda)の励起光に対する蛍光のスペクトル強度I_o(\lambda)を以下のようにモデル化しています。

  •  I_i(\lambda): 励起光のスペクトル強度
  •  I_o(\lambda): 蛍光のスペクトル強度
  •  E(\lambda): 励起スペクトル
  •  F(\lambda): 蛍光スペクトル
  •  K: 励起に関する係数
  •  \eta: 蛍光の強度を表す係数(  \eta = 2.0 \times 10^{-2} と設定)
 \displaystyle
I_o(\lambda) = KF(\lambda)
 \displaystyle
K = \eta \int_\Lambda E(\lambda)I_i(\lambda) d\lambda

 K における積分モンテカルロ積分を用いて、以下のように計算します。

  •  p(\lambda_j): 波長 \lambda_j がサンプリングされる確率
 \displaystyle
K = \eta \frac{1}{N}\sum_{j = 1}^{N} \frac{E(\lambda_j)I_i(\lambda_j)}{p(\lambda_j)} \Delta \lambda

また、波長をサンプリングする際、光源と蛍光分子の特性に基づいて波長を確率的にサンプリングしています。

  •  p_F(\lambda): 蛍光分子の蛍光スペクトルを考慮したPDF(確率密度関数)
  •  k_{F_t}: 各波長における蛍光スペクトルの値の総和
  •  w_{F_t}: 蛍光分子を含有した物体の面積とを k_{F_t}考慮した重み
 \displaystyle
p_F(\lambda) = \sum_{i = 1}^{N_\lambda} w_{F_t} \frac{F_i(\lambda)}{k_{F_i}}
 \displaystyle
k_{F_t} = \int_{\Lambda} F_i(\lambda) d\lambda

光源のスペクトルを考慮したPDF  p_L(\lambda)についても p_F(\lambda)同様に計算します。

そして最終的に、蛍光スペクトルに対する重み w_Fと光源に対する重み w_Lで重み付けしたPDF  p_{FL}(\lambda)を用いて波長を多重重点的サンプリング(Multiple Importance Sampling)します。

 \displaystyle
p_{FL}(\lambda) = w_F p_F(\lambda) + w_L p_L(\lambda)

Spectral Rendering of Fluorescence using Importance Samplingより引用

レンダリングの際にはPPPM(Probablistic Progressive Photon Mapping)を用いてレンダリングパス毎にフォトン、レイに割り当てる波長をサンプリングしています。

BBRRDFを用いた手法

Alisaらは蛍光と非蛍光の反射を表現するために、物質中に含まれる蛍光分子の含有率を考慮したBBRRDF(Bispectral Bidirectional Reflection and Reradiation Distribution Function)をモデル化しています。

BRDF(双方向反射率分布関数)に対して、BispectralReradiation が追加されているように、位置と方向に加えて、入射時(吸収される光)の波長と出射時(蛍光として放出される光)の波長に依存した関数です。

  •  a(\lambda): 励起スペクトル
  •  e(\lambda): 蛍光スペクトル
  •  r(\lambda): 反射率スペクトル(非蛍光成分)
  •  Q: 蛍光分子の吸収するエネルギーに対して放出するエネルギーの比率
  •  \delta_{\lambda_i, \lambda_o}: 非蛍光成分において入射波長 \lambda_iと出射波長 \lambda_oを切り替えるデルタ関数
  •  f_{fluor}: 蛍光BBRRDF
  •  f_{nonfluor}: 非蛍光BBRDF
 \displaystyle
f_{fluor}(\lambda_i, \omega_i, \omega_o, \lambda_o) = \frac{c a(\lambda_i) Q e(\lambda_o)}{\pi}
 \displaystyle
f_{nonfluor}(\lambda, \omega_i, \omega_o) = \frac{(1 -c) a(\lambda) r(\lambda)}{\pi}

これらを合わせて、BBRRDFは以下のように表現されます。

 \displaystyle
f_r(\lambda_i, \omega_i, \omega_o, \lambda_o) = \frac{\delta_{\lambda_i, \lambda_o} (1 -c a(\lambda_i)) r(\lambda_i) + c a(\lambda_i) Q e(\lambda_o)}{\pi}

 \omega_i,  \omega_oを引数に持つように、入射と出射の方向の観点では相互作用を起こしそうですが、蛍光現象おいてはストークスの法則があるため、一般的に放出された蛍光による相互作用(二次蛍光)は起こりません。

 c, Q, a(\lambda), r(\lambda) [0, 1]の値をとり、 c = 0の場合は非蛍光の完全拡散反射BRDFになります。

波長のサンプリングとしては、以下の2ステップで行っています。

  1. 蛍光現象が発生するかをサンプリングする
  2. 新しい波長をサンプリングする

まず蛍光現象が発生するかについては、光源パスで発生する確率 P_lとカメラパスで発生する確率 P_cによって決定します。

 \displaystyle
P_l = \frac{c a(\lambda_i) Q}{c a(\lambda_i) Q + (1 - c a(\lambda_i))r(\lambda_i)}
 \displaystyle
P_c = \frac{c \int_\Lambda a(\lambda) d\lambda Q e(\lambda_o)}{c \int_\Lambda a(\lambda) d\lambda Q e(\lambda_o)+ (1 - c a(\lambda_o))r(\lambda_o)}

これらの確率は光源パス、カメラパスで反射された(蛍光現象によるエネルギーも含む)エネルギーに対する、蛍光として反射されたエネルギーの割合です。

 P_l の場合は光源から照らされて吸収される入射波長 \lambda_i P_c の場合は蛍光現象によって放出される出射波長 \lambda_oが与えられます。また、 P_lの分母の第1項の蛍光スペクトルの積分 \int_\Lambda e(\lambda) d\lambda = 1 として省略されています。

蛍光現象が発生したと決定した場合は、使用した確率に応じて波長をサンプリングする際に用いるPDFが変わります。

  • 光源パス( P_l): 蛍光スペクトル e(\lambda)をPDFとする
  • カメラパス( P_c): 励起スペクトル a(\lambda)をPDFとする

光源パスの場合は、光源 => 光の吸収 => 励起状態 => 光の放出 => カメラ

また、カメラパスの場合はその逆順の過程を経ることに注意が必要です。

A Simple Diffuse Fluorescent BBRRDF Modelより引用

左図は蛍光物質の球がUVライトによって照らされたシーンです。

右図において、横軸は左端を0、右端を1として吸収したエネルギーに対して放出したエネルギーの比率 Qを表し、縦軸は上段から c = 0, 0.2, 0.4, 0.6, 0.8, 1を表しています。

まとめ

今回は蛍光現象とそのレンダリング手法について紹介しました。 暗闇で仄かに輝く蛍光や燐光かっこいいですよね!

冒頭で紹介した蛍光スペクトラルビューアーは蛍光色素のスペクトルデータを出力したり、グラフを画像として書き出すことも可能です。 ポチポチしているだけでも割と楽しいので気になった方は是非遊んでみてください!

本来は蛍光物質のボリュームレンダリングについても紹介したかったのですが、間に合いそうになかったので今回はここまでにしたいと思います...。

それでは!

参考文献