本記事は ZOZO Advent Calendar 2023 カレンダー Vol.5の14日目の記事です。
昨日の投稿は @zzt-osamuhanzawa さんの 「Jetpack Composeを使ったSwipeableなPopup UIの実装」でした。
こんにちは、ML・データ部の @tama_Ud です。
ライトアップでウキウキのクリスマスシーズンにちなんで、光の性質を真珠の構造を通して学んでみました。
業務にミリも関係ないネタですが、雑学本を読むような感じで気軽にお楽しみください。
はじめに
真珠ってきれいですよねえ。
この輝き、CGで再現してみたい......。
一見ただの球ですし、余裕で作れそうに見えますが、実は真珠の輝きには色々な光の性質や現象が隠れています。
まずは真珠の構造から紐解いていきましょう。
真珠の構造
1.表面が多層構造
真珠表面は多層構造になっているそうです。
核を中心に、炭酸カルシウムとコンキオリンと呼ばれるタンパク質が何層も重なって真珠層をつくります。
参考:
2. 透過・散乱反射・干渉が起こる
真珠の構造はガラス玉や金属球とは異なるということです。
構造が異なれば、反射の仕方も異なります。そして反射が異なれば見え方も異なります。
真珠に光が当たると、金属球のようなピカピカとした反射ではなく、ぼんやりと光のベールを纏ったような反射を起こします。
これは光が真珠層を通過するときに透過・散乱反射・干渉という物理現象が起きるからです。
反射光の経路のイメージ。
層内で色んな方向に光が折れていることがわかります。
画像引用: https://www.jstage.jst.go.jp/article/gsjapan/23/1-4/23_KJ00005607748/_article/-char/ja/
この反射や干渉が、真珠表面に独特の光沢と色を与えているんですね。
3. 真珠の色の構成
真珠の色は物体色(実体色)と光沢色(構造色)の組み合わせから成ります。
-
物体色(実体色)
層内の色素による選択吸収を受けながら真珠層を拡散透過するもの -
光沢色(構造色)
表面からの反射光に、真珠層から反射した光が作用し合い干渉色を伴って現れるもの
ざっくり言えば真珠自体の色が物体色です。
「光沢色(構造色)」とはなんでしょうか?
身近ではCD (今、身近なのだろうか...?) やシャボン玉の表面に見られる虹色のアレのことです。
見る方向によって表面がさまざまな色に変化しますよね。
真珠の表面でも同じ現象が起こっているんです。
4. つまり?
つまり、真珠の光沢と色をシミュレートするには、表面で反射する光に加えて、内部の層を透過・散乱する光、光路差で干渉を起こす光......と、複数種の光の経路を考慮する必要があるわけですね。
美しいのは大変結構なのですが、正確な光路シミュレーションのコストが高いということでもあります。
シミュレートしてみる
調べた感じではデファクトスタンダードとなる真珠表面の拡散反射の実装はなさそう、かつ真珠の反射・透過率を知るには実物の計測が必要なので、こちらの論文を読んで進めます。
1.透過・反射率の式
上記論文の数式と係数を用いて、RGBの色を照射したときの、真珠の透過・反射率を求めます。
透過率 (Ts), 反射率 (Rs)
T_s = \frac{(1 - A^2) \exp(-\alpha \tau)}{1 - A^2 \exp(-2\alpha \tau)}
R_s = \frac{1 - \exp(-2\alpha \tau)}{1 - A^2 \exp(-2\alpha \tau)}
吸収率 (A)
\alpha = \sqrt{K(K + 2S)}
A = \frac{K + 2S - \alpha}{K + 2S + \alpha}
散乱媒質の無次元吸収係数 (K) と散乱係数 (S)
K = \left(\frac{300 \times 10^{-9}}{\lambda }\right)/\tau
S = \left[\left(\frac{500 \times 10^{-9}}{\lambda}\right)^{4}\right]/\tau
散乱媒質は、今回は真珠の層になります。
τ は "optical length of the scattering medium" と説明されています。訳すと「散乱媒質の光学的長さ」つまり真珠の層の厚みと解釈できますね。
真珠は「光の波長程度の周期をもつ多層構造」から成るとあるため、真珠の層の厚みは可視光の波長 (360~830[nm])のうちいずれかで固定できると考えます。今回 τ はRGBのRの波長=700[nm]とします。
また、λは変数で、入射光の持つ波長 (wavelength) です。
2. 透過・反射率の導出
R,G,B三原色の光を当てた時の、真珠の透過・反射率を求めてみます。
シミュレートとは言っても、先ほどの式に代入するだけですので、正確には検算です...... (先人の知恵に感謝)。
λに R=700, G=546.1, B=435.8 [nm] を代入して計算します。
以下、申し訳程度のpythonスクリプト(電卓用途)です。
# K
>>> K_lambda=546.1*math.pow(10,-9)
>>> (K_bunsi/K_lambda)/K_bunbo
784785.6227273915
# S
>>> S_lambda=546.1*math.pow(10,-9)
>>> (S_bunsi/S_lambda)**4/S_bunbo
1003906.5115973328
# alpha
alpha=math.sqrt(K*(K+2*S))
# A
>>> A_bunbo=K+2*S+alpha
>>> A_bunsi=K+2*S-alpha
>>> A=A_bunsi/A_bunbo
>>> A
0.4213721211550492
# Ts
>>> Ts_bunsi=(1-A*A)*math.exp(-alpha*tau)
>>> Ts_bunbo=1-(A*A*math.exp(-2*alpha*tau))
>>> Ts=Ts_bunsi/Ts_bunbo
>>> Ts
0.32517453836955906
# Rs
>>> Rs_bunsi=1-(math.exp(-2*alpha*tau))
>>> Rs_bunbo=1-(A*A*math.exp(-2*alpha*tau))
>>> Rs=Rs_bunsi/Rs_bunbo
>>> Rs
0.8846373784079427
...
R < G < Bの順に反射率が高く、反対に透過率はR > G > Bの順になっています。
論文の透過・反射特製の計測結果と対応していることがわかりますね。
おわりに
安易にネタを決めた結果、全てがめちゃくちゃに難しくて地獄をみました。
とはいえ、光の性質に興味を持ち始めたところだったので、良い学習の機会にできたと思います。
まだまだきちんと理解できていないので、詳しい方はぜひご教示ください。
GLSLで実装までできるとよかったのですが、フラグメントシェーダーを書くところで時間ぎれに。興味ある方はぜひ実装もやってみてください。
明日は @YasuhiroKimesawa さんの「FeatureFlagを使った機能のE2Eテスト」 です。お楽しみに!
おまけ
ちなみにコスメのパール材やラメ材も、干渉の性質を応用することで作られているそうです。
パール材のマイカに黒い膜を巻いて、さらにその上から白い膜を巻いて干渉を調整するのは、真珠の核の色が干渉色に影響を与える現象と同じですね。
人工的に真珠の核の色を暗くする技術もあるそうです。へー。
下地の色がパール材の発色に影響する説明はこちらがわかりやすかったです。
参考・引用
- Ryotaro Ozaki."Structural colors of pearls".Scientific Reports.2022. https://www.nature.com/articles/s41598-021-94737-w
- 三宅洋一. "色彩工学の基礎". 日本画像学会誌. https://www.jstage.jst.go.jp/article/isj/49/3/49_3_214/_pdf
- https://edu.jaxa.jp/contents/other/if/pdf/in_vivo.pdf
- シーシーエス株式会社「第29回 色の客観的な表現と伝達 (その3)」 https://www.ccs-inc.co.jp/guide/column/light_color/vol29.html
- テクノ・シナジー「構造色とは」http://www.techno-synergy.co.jp/opt_lectures/about_SColor05.html
- 「構造色レンダリングの要点をまとめてみる」
https://light11.hatenadiary.com/entry/2018/05/06/231014