最後の映り込み
![]()
![]()
![]()
・映り込み第三弾
「映り込み・床編」、「映り込みと床と影と」に続いて、床への映り込み最終回です。いい加減これで床への映り込みは最後にします。初めは1回で終わらせるつもりだったんですけどね。
今回は、前回言った「加算合成を使わない映り込み」と「光源とモデル(物体)の反転」の2つについてです。
・加算合成を使わない映り込み
解説の前に、映り込みの手順のおさらいをしましょう。これを書いている自分が覚えてないですし。
まず移りこむ位置に物体を描画します。この時明度は床の映り込む割合、つまり鏡面反射率の分だけ落とすんでしたね。25%映り込むなら明度も25%に。次に床を加算合成で描画。床の明度は移りこまない割合、拡散反射率の分落とします。最後に物体を普通に描画します。
映り込んだ物体を
明度を落として描画
…よく見えないけど→
床を加算合成で描画→
そして物体を
普通に描画今回は、説明しなければいけないことが増えるので影は使いません。影を使うことで発生する問題と、その解決の方法は加算合成を使う場合も使わない場合も同じです。問題と解決方法については前回の「映り込みと床と影と」を参照のこと。
補足。影を使う場合の描画順は床→映り込み物体加算→物体でしたが、こうすると前回説明したとおり映り込んだ物体のオーバードロー問題をなんとかしないといけません。前々回や今回のように映り込み物体→床加算→物体とすると床のオーバードローを解決する必要がありますが、平面の床ならオーバードローはほとんど無いので気にせずに済みます。
加算合成による映り込みは、映り込む物体を明度を落として描画し、床も明度を落として描画します。それなら、映り込む物体は普通の明度で描画して、床を描画する時に一緒に明度を落としても同じことができます。それが加算合成を使わない映り込み、つまり半透明を使った映り込みです。拡散反射率が75%、鏡面反射率が25%の場合、映り込む物体を明度25%で描画して、床を明度75%で加算合成します。これを半透明でやるなら、映り込む物体の明度はそのままで、床を不透明度75%にすると、映り込み25%床75%になります。
映り込んだ物体を
普通の明度で描画→
床を半透明で描画
この画像では87.5%
(7/8)の不透明度→
そして物体を
普通に描画物体の光源処理がリアルタイムじゃない場合、物体の明度を一つ一つ落とす処理が必要ですが、この方法なら物体の明度は気にする必要が無いです。
その代わり、この方法には欠点もあります。それは、物体を先に描画するため、明度のクリッピングを先にしてから明度を落とすということです。と言われても何が何やら。
通常、明度1.0(表示できる最大明度)以上の明度の色を描画しようとした時は、明度を1.0にして描画します(クリッピング処理)。
クリッピング処理は描画する時に実行します。加算合成を使った映り込みでは、物体は明度を下げてから描画します。半透明を使った映り込みでは、物体は描画してから明度を下げます。例として、rgb( 0.5, 2.0, 3.0 )の色の物体が鏡面反射率25%の床に映り込む時の、映り込んだ物体の色を比べてみます。
加算合成:明度を25%[rgb( 0.5, 2.0, 3.0 ) → rgb( 0.125, 0.5, 0.75 )] → 1.0でクリッピング・描画[rgb( 0.125, 0.5, 0.75 ) → rgb( 0.125, 0.5, 0.75 )] こんな色→■
半透明:1.0でクリッピング・描画[rgb( 0.5, 2.0, 3.0 ) → rgb( 0.5, 1.0, 1.0 )] → 明度を25%[rgb( 0.5, 1.0, 1.0 ) → rgb( 0.125, 0.25, 0.25 )] こんな色→■
上が黒からrgb(0.5,2.0,3.0)のグラデーション(クリッ
ピングあり)、下が加算合成の場合の映り込み
上は同じで、下は半透明による映り込み
上のグラデーションをそのまま25%にした感じこのとおり、半透明では明度1.0を超える部分が加算合成よりも暗くなってしまいます。床の鏡面反射率が25%なので、明度の最大も25%(0.25)になっています。この画像を見ると半透明のほうが正しいようにも見えますが、実際には加算合成の例の方が正確だし色も鮮やかです。
使い方によっては明度が1.0を超えることもそうないですけど、スペキュラー(鏡面反射)を使うと簡単に超えてしまいます。あとエフェクトのためにやたら強い光源を使ってみたり。
……加算合成を使わない映り込みについて説明してみましたが、これって何の役に立つんですかね?スターフォックス64(任天堂)でやってたので書いてみたんですが、N64は加算合成が使えないから半透明を使ってるんですけどね。あとセガのMODEL3のレースゲーム(名前忘れた。セガラリー2ではない)でもやってたような。
半透明しかできないハードとか、加算より半透明がかなり速いハードとかなら役に立つかもしれませんけど。
・お手軽反転
映り込んだ物体の位置を求めるには、床について反転させるんでしたね。
物体を反転させる光源の位置や方向も反転させます。
この場合光源はもちろん、Direct3Dでいうワールド行列(オブジェクト座標系からワールド座標系へ変換するための行列)もすべて反転させなければいけなくなり、手間と計算量が増えてしまいます。この方法よりは計算量と手間を少なくできる方法があります。
物体も光源もすべて反転している。目に見えるものはすべて反転している。でも、1つだけ反転していないものがある。それはカメラ。目に見えるものは反転しても、カメラ(視線の元)の位置や方向は変わっていない。だったら、目に見えるものは反転しないで、カメラを反転させれば良いということになる。これなら手間も計算量も最初の方法に比べれば減少する。
では実際にやってみましょう。この例では、前半で説明した半透明による映り込みを使ってみます。
最初にカメラだけを反転。
物体や光源はそのまま→
普通に描画。床は裏面
除去で描画されない→
カメラを元に戻して→
床を半透明で描画→
物体を普通に描画ご覧のとおりちゃんと映り込んでます。半透明を使う方法だと、反転だけではなく描画も普通にできて手間が省けます(明度を指定しなくていい)。もちろんこの反転方法は半透明専用ではないので、床に加算合成を使う方法と組み合わせて使うこともできます。
反転については以上。なんだか短く終わってしまいましたね。
・映り込み完結
当初1回で済ませるはずが、3回に渡ってやることになってしまった床への映り込みも、ひとまずこれで終了ということにさせていただきます。映り込んだ時の明度についてはあまり自身が無いですが……。
次回の更新については、まったく目処が立っておりません。4/1に就職するため、それからは暇ができるかわからないので。一応目標はsubject z まで行くことなんですが……。ちなみに今回はsubject u なので、v w x y zで残り5回ですね(この後subjectとtopicとに分けました)。
最近実験してみたいことは、フィードバックエフェクト。FF7をやった時に、戦闘に入る時のエフェクトの真似をDirectDrawでやったんですけど、それをDirect3Dでやりたいなぁと前々から(1年前以上?)思っています。それがFF8をやったら再燃してきました。
![]()
![]()
![]()
written by Y.Ohde e-mail : oode@alles.or.jp