チュートリアル35

ライティングとフォグ


ライティング ―現実の世界での対象物の照明ー これはとても難しい問題です。私達が対象物を見るとき、私達の目は焦点を合わせ、可視光と呼ばれるエネルギーの範囲に渡って光子を検出します。光子は、太陽、照明、蛍、もしくは他の光源と私達の目の間で、様々な素材による反射や屈折をしたり、大気で散乱したりして、多くの複雑な経路を通ってくることができます。私達のコンピュータは近いうちにはこのレベルの複雑性を扱うことはできないでしょう。ですから、OpenGLではそれを非常に単純化しています。


OpenGLライティングモデル

OpenGLでのライティングは、現実世界での出来事の非常にラフなモデルを基にしています。自然の巧妙さに比べればとても大雑把なものですが、現在の技術で、リアリズムへの欲求と複雑さのコストを天秤にかければ、良い妥協と言えるでしょう。

これまでに私達は、OpenGLでの色がRGB(赤、緑、青)値としてどう表現されるのかを見てきました。OpenGLでのライティングモデルは、RGBの3要素のように、各種の独立要素による表現で光の指定を可能にするため、この考え方を拡張します。各要素は、ある種の方法で散乱された光がどの程度の色になるのかを表します。現実世界であり得る光の道筋は、4つの要素に単純化されます。ここで、それらを方向性のあるものから方向性のないものの順で挙げます。

鏡面反射光(specular light)要素は、ある方向から来て、表面で主に特定の方向に反射する光です。艶のある素材は、顕著な鏡面反射要素を持っています。鏡で反射する集中した光線では、鏡面反射要素が目立つ状況になるでしょう。

拡散反射光(diffuse light)は、光が一方向から来ますが、表面での反射はすべての方向に等しく散乱します。もし、その表面が光源に対面していれば、光源から受ける光の放射は大きなものになり、表面から反射される拡散反射要素が非常に明るくなります。もし、表面が別の方向に向いていれば、光源に向かう断面積は小さくなり、拡散反射要素は小さくなります。

環境光(ambient light)には方向性がありません。非常に散乱した光であるため、その光源の方向が定まりません。そして全方向から等しく光っているように見えます。白い壁の部屋は、高い環境光要素を持つ環境です。なぜなら、とても多くの光子が私達の目に届く前に、壁から壁へ反射し、散乱するからです。

最後に、放射光(emissive light)があります。これは方向にはまったく影響されません。そのオブジェクトを直接見た場合にだけ、あなたの目に届く光です。これは、モデリングするオブジェクト自体が光源となる場合に使います。

これらの要素は、素材や光源を表現するために使われます。鏡面反射光要素、拡散反射光要素、環境光要素、放射光要素で作られる素材は、ポリゴンがどんな色になるのかを決定するために用いられます。素材を持つポリゴンは、そのシーンでの環境光要素に加え、光源やカメラに対するそれらの位置や回転角、さらに光源の鏡面反射や拡散反射のプロパティに応じて明るくなります。


最初に

・Jitter Tutorialフォルダにある35jLightingAndFog.patというチュートリアルパッチを開いて下さい。Start Renderingというラベルが付いているtoggle(今回は左下にあります)をクリックして下さい。

jit.pwindowオブジェクトの上にあるname lt, depthbuffer 1と書かれたメッセージボックスをクリックしてください。これはデプスバッファを生成するので、隠れた面の除去が可能になります。

jit.pwindowオブジェクトに平坦なグレーのトーラスと小さな白い円が見えるでしょう。そのチュートリアルパッチの真ん中にあるjit.gl.gridshapeオブジェクトがトーラスを描いています。パッチの右側にあるもう一つのjit.gl.gridshapeオブジェクトは、白い円を描いています。このシーンではライティングがまだ有効になっていないため、すべて平坦な陰影で表されています。

・上部にあるlighting_enable $1、smooth_shading $1、auto_material $1と書かれた3つのメッセージボックスの上のtoggleボックスをクリックしてください。これはトーラスを描くjit.gl.gridshapeオブジェクトのそれらアトリビュートに1を設定します。

各オブジェクトに対して、ライティングはデフォルトでオフになっているので、それを有効にしなければなりません。スムースシェーディングについても同じことが言えます。これら2つのアトリビュートを設定すると、(このチュートリアルを順番に進んできたとすれば)もうお馴染みの経過を経て、平坦な陰影から切子面に、そして立体的で滑らかなものになっていくでしょう。auto_materialアトリビュートを1に設定したときには、何の変化も見られないでしょう。なぜなら、その値はデフォルトですでに1だからです。

・auto_material $1というメッセージボックスの上にあるtoggleオブジェクトをもう一度クリックしてください。これはjit.gl.gridshapeオブジェクトのauto_materialアトリビュートに0を設定します。
今度はトーラスのライティングに変化が見られるはずです。最初からの光沢のないグレーの外観に変わって次のような光沢のあるグレーの外観が見られるでしょう。


auto_materialアトリビュートをオフにして照らされたトーラス

単にオブジェクトが照らされるのを見るために、必ずしも素材のすべての要素を指定する必要がないように、Jitterではauto_materialアトリビュートが提供されています。GLグループのオブジェクトのauto_materialアトリビュートがオンでオブジェクトへのライティングが有効なとき、オブジェクトに対する拡散反射と環境光の素材要素がオブジェクトの色に設定され、鏡面反射と放射光要素は無効になります。これは、最初に見た平坦なグレーのトーラスのような結果になります。しかし、このチュートリアルでは、すべてのライティング要素が明示的に指定されているときに何が起こるかを見たいため、auto_materialアトリビュートをオフに変更しました。

その結果のイメージは輝いて見えます。それはト―ラスに適用された素材が鏡面反射要素を持つからです。


ライトの移動

白い円を描くjit.gl.gridshapeオブジェクトには、jit.gl.handleオブジェクトがつながっています。これまでにも見てきたように、これは、その円をクリックしてコマンドキーを押したままドラッグすることで動かせるようにします。オプションキーを押したままドラッグすれば、その円をそのシーンでのカメラに対して近付けたり離したりすることができます。

このjit.gl.handleオブジェクトからのx、y、z位置の値も、unpackオブジェクトを経由し、目で見えるようにナンバーボックスオブジェクトへ送られます。pakオブジェクトは、light_positionシンボルを先頭に加え、リストの終わりにもう一つの値を加えます。このメッセージは、そのシーンのライトの位置を設定するためにjit.gl.renderオブジェクトへ送られます。ライトは、他のオブジェクトでその影響が見えるだけで、ライト自体は見えないことに注意してください。白い円は、ライトの位置を見るために使うことのできる印なのです。

・白い円をコマンドキーを押したままクリックし、そのままドラッグしてシーンの左下隅へ移動させてください。それから、オプションキーを押したままドラッグし、カメラから離してください。

光源は白い円とともに移動します。もし、正しい位置に移動していれば、次のようなイメージを生成することができます。


同じシーンで光源を移動したもの

光の拡散反射と鏡面反射の要素は、光の位置と、カメラの位置に向かって反射する光の角度に従って、各頂点で素材の拡散反射と鏡面反射の要素が組み合わさります。ライトを移動させたとき、これらの関連位置が変わるため、各頂点が様々な色になります。

法線:ライティングを開始するために、モデルの各頂点には対応する法線がなければなりません。法線は、その頂点でオブジェクトの表面に対して垂直に定義されるベクトルで、それはイメージの鏡面反射や拡散反射要素の影響分を決定するのに使われる値です。複雑なオブジェクトに対する適切な法線の生成は、時間のかかる処理になってしまいます。

Jitterは、この不安を2通りの方法でできる限りなくそうとしています。まず、GLグループのほとんどのオブジェクトにはそれらに対応した法線があります。これらは、描画を行うオブジェクトによって計算されます。jit.gl.gridshapeオブジェクトはその一例です。その形状として球が設定されたときには、球の中心から外側に向かった法線が、各頂点で生成されます。各々の形には法線計算の様々な方法があるため、様々な形の表面は、曲線を描く部分では滑らかですが、立方体のような形の縁ではくっきりとして滑らかではないままになります。

次に、jit.gl.renderオブジェクトに対して直接ジオメトリをマトリクスで送った場合、jit.gl.render オブジェクトはその能力を最大限に使って自動的に法線を生成します。tri_gridやquad_gridプリミティブが後に続くマトリクスを送ることによって、結合したグリッドのジオメトリを描画する場合、生成された法線はグリッドの表面を横断して滑らかにされます。もし、三角形のような他のプリミティブを使ったマトリクスを送るのなら、jit.gl.renderはその頂点を滑らかにせずに、ジオメトリにおけるそれぞれ別個のポリゴンに対して法線を生成します。

もし、自分自身の法線を作りたければ、jit.gl.renderオブジェクトのauto_materialsアトリビュートに0を設定することによって法線の自動生成をオフにできます。

チュートリアル37の「Geometry Under the Hood:フードの下のジオメトリ」では、Jitterマトリクスを通して、頂点、色、法線がどのようにjit.gl.renderオブジェクトへ渡されるかを解説しています。マトリクス内のジオメトリに対する法線を指定する方法の詳細については、このマニュアルのJitter OpenGL Appendexを参照してください。


鏡面反射光

ライティングの鏡面反射要素をもっと良い感じになるように変えてみましょう。

・prepend mat_specularオブジェクトの上のswatchオブジェクト(色見本)を見つけてください。その色見本の中の円を左端に寄せてください。これは、jit.gl.gridshapeオブジェクトに、純粋な赤を表すRGB値が続くmat_specularメッセージを送ります。

swatchオブジェクトは、0から255の範囲の3つの整数のリストを出力します。vexprオブジェクトは、JitterのGLグループオブジェクトが鏡面反射の色として使う0.から1.の範囲の浮動小数点値を生成するために、それぞれの整数値を255.で割り算します。


鏡面反射素材の要素への赤の設定


赤いハイライトの結果のトーラス

いま、イメージのハイライトは赤い色になっています。このとき、白い光源の鏡面反射要素には、ハイライト色を生じさせるための鏡面反射素材の要素が掛け合せられています。

鏡面反射光源の赤、緑、青の値は、それぞれ鏡面反射素材の要素の赤、青、緑の値が掛け合わされています。そのため、光源の要素と素材の要素が違う色ならば、結果がゼロになる可能性もありますし、ハイライトは生成されません。これは、赤い照明の部屋で緑の物体を見たとき、その物体は黒く見えるというような、現実世界での光と素材との作用が多少なりともモデルになっています。

prepend light_specularオブジェクトの上のswatchオブジェクトで、円を緑色のところに移動させてください。ハイライトが見えなくなるでしょう。赤の量の変化で異なった色は、異なった赤の輝きを生み出します。それを終えたら、ハイライトを赤に戻すためにswatchオブジェクトの上部へ円を移動させてください。

GLグループのオブジェクトのshininessアトリビュートは、素材定義での重要な部分です。これは、光がオブジェクトに反射するとき、どの程度の光が拡散したり、広がるのかを指定します。鏡をモデル化するためには、非常に高い値のshininessを使うべきです。現実的なオブジェクトを作成するためには、およそ2から50の値が使われます。

prepend shininessオブジェクトの上のナンバーボックスを50に設定してください。

これで、鏡面反射光要素の影響領域がさらに狭くなります。それによって、グレーのままの拡散反射光から完全に際立った赤の鏡面反射光を見ることができます。


非常に輝きのあるトーラス


拡散反射光

拡散反射要素の影響を見るために、もう少し色を操作してみましょう。

・prepend mat_diffuseオブジェクトの上にあるswatchオブジェクトを見つけてください。拡散反射素材の要素を深い青にするため、swatch内の円をおよそ下の図の位置に動かしてください。


拡散反射素材への青の設定

トーラスからの拡散反射は青で、ハイライトはマゼンタになります。これは、位置によってライティング要素が掛け合わされた後、各頂点でオブジェクトに対する最終的な色を作り出すために、オブジェクトの素材の色要素が一緒に加えられたためです


青い拡散反射光に赤いハイライトが加えられました


環境光

私達は、オブジェクト素材の環境光要素をまだ変えていません。現在、これはデフォルトの中間的なグレーに設定されていて、上の図でのトーラスの暗いグレー領域を作り出すために、全体的な環境光要素である暗いグレーが掛け合わされています。全体的な環境光要素は、あるシーンにおけるすべての環境光素材の要素が掛け合わされるもので、各オブジェクトの各頂点に加えられます。これは、jit.gl.renderオブジェクトのlight_global_ambientアトリビュートで設定できます。

・緑の環境光素材の要素を生み出すため、prepend mat_ambientの上のswatchオブジェクトにある円を緑色に設定してください。


緑の環境照明


環境光素材の要素は、グレーの領域から置き換えられた暗い緑色の領域を作るために、全体的な環境照明要素が掛け合わされています。

そのシーンで動かせるライトは、全体的な環境光要素が加えられて結び付いた環境光要素を持っています。これを変えるため、prepend light_ambientオブジェクトの上にあるswatchオブジェクトの円を動かすことができます。もし、これを明るい色にすれば、環境光要素の輝度が拡散反射光よりも高くなるため、オブジェクト全体の外観が明るくなります。


これは見苦しい!

青い拡散反射光とマゼンタのハイライトを持つ緑色のトーラスは、おそらくあなたが長らく見たかったものではないでしょう。もし、まだ色見本で遊んでもっと調和の取れた組み合わせを見つけだしていないのなら、いまがそれを行うのにちょうど良い機会になります。

このパッチではスペースの都合で、彩度の制御は行っていませんが、すべてのライティングと素材の要素に対して彩度を減らした色を指定することもできます。


方向性 vs. 位置性のライティング

あるシーンで動かせるライトは、方向性か位置性かのどちらかにすることができます。jit.gl.renderに送られるlight_position [x] [y] [z] [w]のメッセージで、[w]の値は、方向性か位置性のライティングのどちらが使われるかを決めます。もし[w]がゼロなら、ライトは方向性を持ったものになり、[x]、[y]、[z]の値で、光が来る向きを表す方向ベクトルを指定することになります。[w]がゼロでなければ、ライトは移動可能になり、シーンにおけるその特定位置に基づいてオブジェクトを照らします。ライトの位置は、均一化された[x]/ [w]、[y] /[w]、[z]/ [w]の座標によって指定されます。

位置性のライトは、シーン内での人工的な光源をシミュレートするのに適しています。方向性のライトは、典型的なものとしては太陽の代わりになります。それは、そのシーンにおけるオブジェクトの位置を変えても、光の向きが変わることがわからないほど遠くにあるものです。

・トーラスをカメラに近付けたり遠ざけたりするために、p moverサブパッチの上にあるtoggleをオンにしてください。

トーラスがライトに対して全体的に近付いたところを通るとき、その動きによって、どんなライティングがトーラスの表面を横切っていくのかに注意してみてください。これをよく見るためには、ライトの位置を動かしてみたほうが良いかもしれません。

・方向性のある光の効果を見るため、pak light_position 0. 0. 0. 1.オブジェクトの上にある最後のナンバーボックスを1に変え、それから0に戻してみてください。

ここで、方向性のあるライティングがオンになるので、オブジェクトが位置を変えても、ライティングはもう変わらないことに注意してください。

フォグ

ライティングの他の問題と同じように、OpenGLでのフォグ(霧)のシミュレーションは、現実世界の現象と対応する基本的なものです。さらに、それはイメージに対して豊かな特徴を加えるための便利な方法を提供します。OpenGLフォグは、ライティングの計算が終わった後に、各頂点の色とカメラからのオブジェクトの距離によって量が増えるフォグの色を単純に混ぜ合わせます。そのため、遠くのオブジェクトはフォグの中で見えなくなってしまいます。

Jitterで、フォグはfogアトリビュートを用いてGLグループの各オブジェクトに対してオンとオフが切り替えられます。シーンの中でのいくつかのオブジェクトにはフォグを適用し、他のオブジェクトには適用しないことが可能です。

・fog $1というメッセージボックスの上にあるtoggleをオンにしてください。これは、トーラスを描く jit.gl.gridshapeに対するフォグをオンにします。

pak fog_params…の上の右端のナンバーボックスに対して10という値を設定してください。これで、その同じjit.gl.gridshapeオブジェクトに並んだfogパラメータがすべて送られます。

p moverサブパッチがまだ有効になっていれば、トーラスがカメラから遠ざかるにつれて、フォグの中で薄れていくのが見えるでしょう。

pak fog_paramsオブジェクトの上にある赤いナンバーボックスに1を設定してください。これは、フォグの色を1.、0.2、0.2に指定します。

ここでは、トーラスが離れても見えなくなりません。むしろ、それは明るい赤になります。フォグは、遠くのオブジェクトにフォグの色を多く反映しますが、それは、背景色と同じかどうかわかりません。フォグの色と背景色の色が近いときにだけ、現実的なフォグ効果が実現します。


フォグの中に遠ざかったトーラス

もし試してみたければ、fog_paramsメッセージの上にあるナンバーボックスオブジェクトのフォグに関する他のパラメータを操作してみてください。

実装依存:チュートリアル33で紹介したアンチエイリアシングのように、フォグパラメータの効果はシステムによって様々で、どのOpenGLレンダーが使われているかに依存します。これまで議論してきたフォグの基本特性は、基本的には同じであるべきですが、デンシティ(濃度)パラメータがフォグにどのくらい影響するかというような詳細については異なるかもしれません。


まとめ

OpenGLライティングモデルや、Jitterでのその実装について多少なりとも詳細を交えて説明してきました。OpenGLライティングモデルの鏡面反射、拡散反射、環境光の要素について、また、それらは現実世界のシーンの様々な様子にどう近付くのか、そして、イメージを作成するためにそれらはどう組み合わされるのかということについても説明にしてきました。位置性と方向性をもったもののライティングの違いも紹介しました。最後に、1つのオブジェクトを叩き台として、シーンにフォグをどうやって加えるかのを見てきました。