そもそも反射ってどんな現象だろう?(不透明に限る)
物体が光を反射するときにどのような振る舞いをするのか?を考えてみます。(透明や半透明はおいておきます)
- 不透明な物体表面に光を当てた時に「物そのものの色が見える部分」と「光源の光が反射する部分(ハイライト)」がある
- 「物そのものの色が見える部分」は見る角度を変えても明るさが変わらない
- ハイライトって見る角度を変えると移動する
このように2個の違う反射の種類があり、光の反射はその2種類の合計であるという考え方を「2色性反射モデル」と呼びます。
「物そのものの色が見える部分」を拡散(diffuse)反射、「光源の光が反射する部分(ハイライト)」を鏡面(specular)反射と呼びます。
R_{reflection}(p,\vec{v}) = R_{diffuse}(p,\vec{v}) + R_{specular}(p,\vec{v})
拡散(diffuse)反射(直接光)
実世界でdiffuse反射を体現している物質としては紙や、チョークなどがあります。真正面から見ても横から見ても、紙やチョークの白さ(明るさ)はほとんど変わりません。また物体の色が反映されるのはdiffuse反射です。
点pに入射する光が強いほど点pの反射する光が強くなります。まぁ当然ですよね。入射する光の強さは、光源の強さのほかに、点pと光源の角度によっても変わります(光源によっては光源と点pとの距離も影響しますがおいておきます)。同じ光源でも法線nとの内積が小さければ入射する光の強さも弱くなります。
この反射モデルで有名なのはランバート(Lambert)反射です。
K_{diffuse}(p) : diffuseの時の反射係数を表す関数\\
max(dot(\vec{n},\vec{l}),0) : 光源と法線の内積。0が最低になるようにする\\
L(p):入射する光\\
-----\\
R_{diffuse}(p) = K_{diffuse}(p) * max(dot(\vec{n},\vec{l}),0) * L(p)\\
(R_{diffuse}(p,\vec{v})ではありません。視点に影響しないからです。)
鏡面(specular)反射(直接光)
リンゴのハイライトや車のボンネットなどが実世界でのspecular反射です。視点を変えるとハイライトの位置が移動するように、視点の位置によって反射率が変わります。また、diffuseとちがって光源の色が見えます。
lの正反射であるrの方向にある視点vでは点pは最も明るく輝きます。そしてそこから角度Xだけズレた視点v'では視点vよりは随分暗いですが輝きます。しかしまったく外れてしまった視点v''では全く輝きません。
このハイライトの鏡面反射で古くからあって有名なのはフォンの反射モデルです。フォン反射モデルは下の数式で表現されます。
K_{specular}(p) : specularの時の反射係数を表す関数\\
dot(r,v)^s : 正反射と視線のズレのs乗\\
s : シャイネス(鏡面反射係数)。ツヤツヤ具合。ハイライトの大きさに影響。完全鏡面はs=∞\\
L(p):入射する光\\
-----\\
R_{specular}(p,\vec{v}) = K_{specular}(p) * dot(\vec{r},\vec{v})^s * L(p)\\
この式では角度X( $dot(r,v)$で表現されてる )がすこし大きくなるだけで急激に光が弱くなります。にしてもs乗とはめっちゃ急激に減りますね。
お手軽わかりやすいこのフォンの方程式ですが、以下のような問題があります(らしいです)。
- ハイライト以外の鏡面反射(特に金属)がうまく表現できない。
- それっぽく見えるだけで物理的には間違っている(らしい)。
とはいえ、それっぽく見えるし、簡易な計算方法もあり(詳しくはリアルタイムシェーダー入門をご覧ください)長く使われています。
昨今の物理ベースレンダリングではこのフォンの反射モデルは使われずに別の鏡面反射のモデルが使われています。後々説明できたらと思います。
間接光
間接光は計算しません。終わり。
とはいっても直接光だけだと暗くなりすぎます。影が本当に真っ黒になってしまいます。実世界では間接光がほんのりと照らしているので本当の真っ黒にはなかなかなりません。
そこで環境光(ambient)という光を導入します。どんなに暗くてもぼんやり光る、最低限の明るさです。単純に足すだけの項です。
(画像は光源と物体の照光処理 より引用させていただきました)
以上説明してたdiffuse、specular、ambientを合成して最終の画像を出力します。これが昔のレンダリング方法です。
(画像は光源と物体の照光処理 より引用させていただきました)
次の回では物理ベースレンダリングについて説明できたらと思います。