シャドウ(影)の描画

Irrlichtにはシャドウボリュームの機能があり、シャドウを自動生成できる。
Irrlichtにおいてはデフォルトでデプスフェイル法でシャドウ生成する。
デプスフェイル法の動作原理については割愛するが、下記のページが分かり易い。
現役ゲームプログラマーが教えるシャドウボリューム

ただし、Irrlichtにてシャドウボリュームを使用する場合、複数の注意事項が発生する。(後述)

基本的な手順

前提としてステンシルバッファが有効になっている必要がある。createDeviceExにてSIrrlichtCreationParameters::Stencilbufferをtrueにしておくこと。

次に、SceneManagerに対して、影の色を設定する。下記の例の場合、不透明度100/255で黒い影を落とす。

pSceneManager->setShadowColor(video::SColor(100,0,0,0));

影の色は全体で1つである。光源毎に影の色を変えるといったことは不可である(光学的にもおかしいが)。

さらに、影を落としたい光源について、enableCastShadow(true)を設定する。逆に言えば、このフラグを設定していない光源に対して影は落ちない。

pLight->enableCastShadow(true);
影を落としたい物体について、シャドウボリュームを生成する。これにより、どの物体が影を落とすかを制御できる。
scene::IShadowVolumeSceneNode* psv = pNode->addShadowVolumeSceneNode();

ここで生成したシャドウボリュームについても、他のノード同様にsetVisibleで不可視設定にできる。不可視にすると影は表示されない。

光源設定

平行光源に対してシャドウを設定しても、正しい方向にシャドウが落ちない。
平行光源主体で使う場合、シャドウ用の点光源を別に用意する必要がある。光量(DiffuseColor)を0にしてもシャドウは落ちるので、シャドウ用光源の光量は0にしてしまってもよい。

モデリングの制約

Irrlicht固有事項ではないが、面で閉じていない物体や、厚さ0の両面ポリゴン物体にシャドウボリュームを設定してはならない。crackと呼ばれる現象が発生してシャドウが破綻する可能性がある。参考画像

遠方クリッピング(setFarValue)

遠方クリッピングをデフォルト以外に変更した場合、addShadowVolumeSceneNodeの第4パラメータのinfinityも変更する必要がある。これをしない場合、シャドウが表示されなかったり、破綻したりする可能性がある。IAnimatedMeshSceneNode::addShadowVolumeSceneNodeのinfinityのパラメータに書かれているが、infinityの値は遠方クリッピングよりも小さい値に設定する必要がある。

テレイン等、巨大物体のシャドウ

Irrlichtのシャドウボリュームは、頂点番号を16bitで管理している。このため、65536頂点以上あるメッシュにシャドウボリュームを設定するとハングアップする。
このような物にシャドウを設定したい場合、65536頂点以下に分割する必要がある。

フォグ

フォグは遠方クリッピングと組み合わせて使うことが多いと考えられる。
Irrlichtのシャドウにはフォグがかからないため、フォグ中でシャドウだけが見えるという現象が発生する可能性がある。この現象が目に余るような状態であれば、距離判定を行ない、適切な距離でsetVisibleによってシャドウボリューム部を非表示(=シャドウ非表示)にする必要がある。
コードとしては下記のようになる。

psv->setVisible(
    pCamera->getAbsolutePosition().getDistanceFrom(psv->getParent()->getAbsolutePosition()) < fogStart);

※psvは前述addShadowVolumeSceneNode()で生成したシャドウボリュームへのポインタ


Copyright by MUTATE Systems 2018
管理者宛メール