プチメタ3.0

刺激を受けた物事に対する感想や考察、資産運用や英語学習、自己成長に関することなど。

非プログラマのための影プログラミング講座

読者の方から、
「プログラム知らないけど興味があるので仕組みを知りたい」
というメールが来たので、ちょっと説明してみる。

●影を表示する2つの意味

そもそもなぜ影を表示する必要があるのか。
ひとつめの理由は単純で、日常生活ではあって当たり前の影を
現実を模したゲームで表示しなければ、不自然さが際立ってしまう。

もうひとつの理由としては

f:id:IKUSHIMA:20180223132904g:plain

キャラクタをきちんと表示していても
画面そのものは平面という2次元のため
遠近感が非常にわかりにくい。

これが、

f:id:IKUSHIMA:20180223132938g:plain

影を表示するだけで、急に距離感がハッキリする。
(キャラクタ本体の高さは2人とも同じであることに注目)

つまり、離れた足場にジャンプで飛び移るようなゲームや、
2Dでも前後の奥行きが重要なゲーム、
たとえば「ファイナルファイト」などは影が必須と言える。

●黒い丸で表現する「丸影」

もっとも簡単に用意できるのが

f:id:IKUSHIMA:20180223133017g:plain

こういう影。いわゆる「丸影」だ。
2Dのゲームでも楕円を描くだけでそれっぽく見える。
3Dの場合でも黒い円を描いた1枚のポリゴンでOK。

ただし、

●キャラクタの形と無関係なので、リアリティが薄い
●途中で折り曲げることができないので
 凹凸のある地面には使えない

という問題が起こる。

●3Dモデルを上下方向に潰した「影モデル」

この次の段階として、3Dのモデルを

f:id:IKUSHIMA:20180223133028g:plain

縦方向につぶし、

f:id:IKUSHIMA:20180223133043g:plain

厚さをゼロにする。

それを黒い色で表示すれば

f:id:IKUSHIMA:20180223133056g:plain

ほら、影っぽい。

本体と一緒に表示してみると、

f:id:IKUSHIMA:20180223133111g:plain

いい感じ。

これだとキャラクタの形がそのまま反映されるので
ぐっとリアルに感じる。
2Dでも同じようなことができるので
これを使っているゲームも非常に多い。

ただし、

●キャラクタのポーズや角度が変わるたびに影の形が変わるので
 影モデルをリアルタイムに作り続ける必要がある
●影そのものは一枚の板なので
 やはり凹凸のある地面には使えない
●厚さがゼロになっただけなので、
 本体と同じだけのポリゴン数を使うことになり、
 処理の負担は大きい

という問題が起こる。

●3Dモデルはポリゴンでできている

そもそも3Dのモデルというのは
「ポリゴン」と呼ばれる、

f:id:IKUSHIMA:20180223133237g:plain

三角形が集まったもの。紙を切り貼りして
立体物を作るペーパークラフトと同じ仕組み。

ポリゴンの頂点の位置が定まれば

f:id:IKUSHIMA:20180223133308g:plain

どういう三角形か特定できるのでポリゴンが描ける。

ちなみに四角形が必要な場合は

f:id:IKUSHIMA:20180223133328g:plain

三角形を2枚組み合わせて使う。

つまり、

f:id:IKUSHIMA:20180223133340g:plain

単純な球に見える3Dモデルでも

f:id:IKUSHIMA:20180223133355g:plain

大量のポリゴンを使って作られている。
ポリゴン数が多ければ多いほど処理は重くなる。

ここまでが3Dの基本。

●3Dモデルの境界部分から作る「シャドウボリューム」

さて、3Dモデルを表示したとき
光が当たるポリゴンと当たらないポリゴンの境目、

f:id:IKUSHIMA:20180223133413g:plain

この直線と、影方向の適当な一点でできる三角形に
新たなポリゴンを作る。

f:id:IKUSHIMA:20180223133437g:plain

これを繰り返して

f:id:IKUSHIMA:20180223133451g:plain

すべての輪郭部分にポリゴンを貼り付けていくと

f:id:IKUSHIMA:20180223133505g:plain

こんな感じになる。

この「輪郭部分がどこなのかをチェックする処理」が
非常に負担が大きく、
当然、本体のポリゴンが多いほど時間もかかる。

この赤く見える部分を「シャドウボリューム」という。

輪郭部分をそのまま平行に押し出した、

f:id:IKUSHIMA:20180223134727g:plain

こういう形の方が理想だが、
シャドウボリュームを作るのに必要なポリゴンが
膨大に増えてしまうため、普通はさっき説明したような

f:id:IKUSHIMA:20180223133505g:plain

影方向に決めた一点とを結んだピラミッドのような形にする。
この影方向にある一点、というのを、ものすごく遠くにすれば
平行に押し出した場合と大きな違いはなくなるのだ。

これは言い換えると、
3Dモデル本体によって光を遮ることになる空間、
ということになる。

これが背景や他の3Dモデルに

f:id:IKUSHIMA:20180223134854g:plain

突き刺さるわけだ。

その際、シャドウボリューム内に
めり込んでいる部分というのは

f:id:IKUSHIMA:20180223134831g:plain

こんな感じになる。
ここは3Dモデルが光を遮っているエリアだから
光が当たらない、つまり影ができるはずである。

画面内でそういう部分だけを抜き出し、

f:id:IKUSHIMA:20180223134800g:plain

これを薄い半透明の黒として画面に重ねると

f:id:IKUSHIMA:20180223134911g:plain

ほら、影っぽい。
もちろんシャドウボリューム自体は表示しない。

今まで問題だった凹凸の面に対する場合でも
正しく影が表示されるわけだ。

ただし、シャドウボリュームの中に入った部分を
すべて影ができるものとして考えるため

f:id:IKUSHIMA:20180223134923g:plain

もともと光が届かないはずの裏側(この画像の青い部分)まで
影として黒く塗ってしまう。

さらにはシャドウボリュームを作るときの処理が多く、
常に形の変化する3Dモデルが大量に出てきて
しかも光が揺れてたり(懐中電灯とか)すると
もう、めっちゃくちゃ大変。
だから「サイレントヒル」とかはスゴイ。
最初にプレイしたとき衝撃を受けた。

もちろん、処理を少しでも軽くするための
さまざまな工夫(でも相当に難しい)や、
シャドウボリューム以外の方法もあるが
とにかく影の処理というのは奥が深すぎるぐらい深いのだ。

●各手法を直感的に理解できる解説動画

※2017年2月 このあたりの内容を説明する動画を作りました