15-06-06《半透明ポリゴンの描画順問題[接触篇]》

元記事:https://archive.md/yAYxe

作成者:不沈空母様

ニコニコユーザーページ:https://www.nicovideo.jp/user/1942311

作成日:2015-06-06 18:00


これもリアルタイム3DCGでは前回の輪郭線の件同様に不可欠な知識だと思うのですが つかリアル系なら輪郭線はあまり必要ないけどこっちは関係なく重要 、やはり定番すぎるためかあまり言及されてない様なので、ここらでひとつ。

自分がこの件に関して詳しく知ったのはntny氏のローポリ本でした。最近だとマシシ本の巻末で言及されてます。


通常、リアルタイムの3DCGはポリゴンを順番に一枚一枚描画する事で表示されています。その描画する順番(描画順)が、半透明な材質やテクスチャを適用したポリゴンにおいてしばしば問題を引き起こす事があります。

・症例

例えばMMDで、ここに半透明のキャノピーを持つ、砂漠を浮いて走る車があるとします。ここにミクさんを読み込んで座席に乗せるとあら不思議、キャノピー越しの部分が消えてしまいます。

【左】砂漠を浮いて走る車。キャノピーは半透明材質を設定

【右】ミクさんを読み込んで乗せると半透明キャノピー越しの部分が消えてしまう


ここでメニューの「背景>描画順の設定」を見ると、読み込み順通りに「車→ミクさん」になっています。つまり半透明のキャノピーの後に、その向こう側に居るミクさんを描画しようとしたために不具合が起こっている訳です。

描画順が「車→ミクさん」の順になっている


描画順を「ミクさん→車」に入れ替えると正しく表示される様になります。「乗り物の前に乗員を描画する」というのが日常的感覚と逆なのでついつい間違えてしまいますがw

「ミクさん→車」に描画順を入れ替えると正常に表示される


他に良く見られるのが、髪の毛の先や樹木の葉など、アルファチャンネルで輪郭を抜いたポリゴンにおいて、輪郭付近のアンチエイリアシング(AA)で半透明になっている部分でこの現象が発生するケースです。

【左】葉の輪郭をアルファで抜いた樹木と、スカイドームの空

【右】描画順が「樹木→空」だとアルファの輪郭部分でスカイドームが消えてしまう


当然、これらの現象はモデルの描画順のみならず、モデルの中でもポリゴンの描画順が不適切だと発生してしまうので、モデル製作者は適切に処理しておく必要があります。

MMDでは材質のID番号順に描画される


もっとも、前後関係がカメラ方向やボーン/モーフ変形などで変わってしまったりする場合もあるので完全には回避できない場合もしばしば生じます。

テクスチャのアルファマスクの対策としては、いっそAAを入れずに白黒二値で描画するという手もあります。ただしGPU側の機能で勝手にAA処理をかけられてしまう場合もあります。なおMMDで強制的に二値化するシェーダーエフェクトを作られた方もいらっしゃいます。

アルファ抜きを行わず、ポリゴンでアウトラインを形作るのが本当は一番良いのですが、細かい部分では大変ですしむやみにポリゴン増えてしまうのも…。

・原因

そもそもどうしてこんな現象が発生するのか、その根本的原因について説明します。

なおこれはあくまで自分なりの考察なので間違っている可能性もあります。まず間違いないとは思いますが念のため。あと知らなくても実用には全く問題ない話なので読み飛ばしていただいて構いません。


3Dポリゴン描画において基本と言えるのが「陰面処理」です。ポリゴンのカメラからの前後関係に基づいて、他のポリゴンに隠れて見えない部分を描画しない事によって、整合性の取れた画面を作り出す必要があります。一番手っ取り早いのは「全ポリゴンのカメラからの距離を測って、遠い物から手前に順に描画する」という手口で、実際そうした処理で表示を行っているケースもあるのですが、これだとポリゴンが交差している場合に前後関係が不定になってチラツキが発生してしまいます。


そこで一般には「Zバッファ法」と呼ばれる方法が用いられています。


ここに2枚のポリゴンA,Bがあります(どちらも不透明)。カメラに対して、BはAよりも離れています。










2枚のポリゴン


まず描画順がA→Bの順に設定されているとします。まずAの描画が行われますが、この際に「Zバッファ」と呼ばれるメモリ領域に、Aとカメラとのピクセル毎の距離が記録されます。A以外の部分は何もないのでそのままです。

続いてBが描画されますが、この際、ピクセル毎にZバッファに記録されている距離とBの距離とを比較して、もしZバッファの方がカメラに近い値 この場合はAの描画された領域 であれば、既にBよりカメラに近いポリゴンが描画されていると判断してBの描画をスキップします。逆にBの方が近ければBを描画して、同時にそのBの距離がZバッファに記録されます。これにより、描画順に関係なくAとBとの前後関係が正確に描画されます。

【上】A→BではまずAのポリゴンが描画され、同時にカメラからの距離がZバッファに記録される

【下】BはZバッファと距離を比較して、Aの描画されてない部分のみが描画される


描画順がB→Aの場合も、同様にZバッファによる比較が行われ、Aは全体がBの手前にあるためにそのまま描画されます。どちらにしろ得られる結果に変わりはありません。

【上】B→AではまずBのポリゴンが描画され、同時にカメラからの距離がZバッファに記録される

【下】AはBの手前にあるため、画面もZバッファも丸ごと上書きされる


ちなみに、一画面全てのポリゴンが描画し終わった時点で、Zバッファには画面全体の奥行き情報が記録されているため、そのまま被写界深度や空気遠近の後処理に使うデプス(深度)チャンネルとして用いる事が出来ます。


では、ここでAのポリゴンを半透明にするとどうなるでしょうか?


描画順がB→Aであれば、Bを描画した上からAが透明度に応じた濃度で上書きされるために自然な描画が行われます。

問題はA→Bの場合です。先程と同様に、Bの描画においてはZバッファを参照して既にAが描画されているピクセルは描画がスキップされてしまうため、結果的にAの後ろの部分はBが消えてしまう現象が発生します。これが半透明ポリゴンの描画順問題の正体です。

【左】B→AではBの上にAが透明度に応じた濃度で描画されて正常な表示になる

【右】A→BではBのAと重なった部分の描画がスキップされて表示されない


なお完全に透明な部分はZバッファへの記録は行われないため、アルファマスクでは境界線のAAによる半透明の部分のみにこの現象が生じる事になります。

【左】アルファマスクで完全に透明な部分はZバッファに記録されない

【右】そのためアンチエイリアスで半透明な境界部分のみに非表示が生じる


この様に、描画順問題はリアルタイムポリゴン描画の大元の部分に根付いている問題であるため、根本的な解決と言う物は存在せず、各自が工夫して対処していくしかありません。

かように厄介な問題ではありますが、時にこれを逆手に取って面白い表現をする事も可能ですので、次回はそれらの手法について紹介する予定です。

今回は何ともツマラない内容で申し訳ありません。次回はもうちょっと面白く実用的な話になると思いますので。

コメント