three.jsでMMDモデルの半透明はどう決まるか|材質の不透明度・モーフ・テクスチャの透明
半透明の材質は、不透明な材質を全部描いたあとに描かれ、後ろが透けて見えます。three.jsでMMDモデルを読むと、どの材質が半透明になるのかを、実物のモデルとMMDLoaderのソースで確かめました。
半透明になる3つの条件
| 条件 | MMDLoaderの扱い |
|---|---|
| 材質の不透明度が1でない | 半透明にする |
| 材質モーフで不透明度が変わる(着せ替え・パーツ消しなど) | モーフの対象の材質を半透明にする(全材質が対象の要素は除く) |
| テクスチャに透明な画素があり、その材質が使っている | 調べるが、結果が材質に反映されない(下で説明) |
実物では、人物Aは53材質中46が半透明になりました。不透明度が1でないのは「瞳レンズ」(0.40)と「胸章」(0.80)の2つだけで、残り44は着せ替え用の材質モーフ(「素足」「デニール」「髪留め」など)が不透明度を変えるためです。アリシアは22材質中3つで、どれも「髪影消し」「照れ消し」のようなパーツを消すモーフの対象でした。
テクスチャの透明の判定は効いていない
MMDLoader には、材質が使うテクスチャの範囲に透明な画素(アルファ253未満)があるかを調べる処理があります。ところが読み込み後に確かめると、判定の結果はテクスチャの側(map.transparent)に書かれるだけで、材質の半透明の設定には反映されていません。 three.js の中に、この値を読む所が見つかりませんでした。
さらに、三角形をたどる変数を3ずつ進めながら、頂点の番号を indices[i * 3 + j] と3倍して引いています。三角形の3つに1つしか調べず、残りは配列の範囲外を読んで素通りします。
正しく数え直すと、アリシアでは22材質中12が透明な画素を使っていました(「tear」は448三角形の全部、「eyebrush」は226中206、「hau」は142中124)。このうち半透明として扱われているのは、モーフの対象になっている材質だけです。
見た目への影響は小さかった
three.js の判定でテクスチャが透明と出たのに半透明になっていない材質(アリシア12・人物A 4)を半透明に切り替えて、顔に寄った正面の画面(1200×900)を比べました。変わった画素はアリシアで16、人物Aで0でした。透明な部分の色が周りと近いか、普段は隠れている材質(涙など)だったためと見られます。このサイトの再生も、ここは three.js のままにしています。
描く順番
three.js は、不透明なものを全部描いてから、半透明なものを描きます。1体のモデルの中では次のとおりです(WebGLRenderer の並べ替えの関数で確認)。
- 不透明な材質は、材質が作られた順(= PMXに書かれた順)
- 半透明な材質は、カメラからの距離で並べるが、同じモデルの材質は距離が同じなので、やはりPMXに書かれた順
- そのため、PMXでは不透明な材質より前に書かれた半透明の材質も、不透明な材質のあとに描かれる
人物Aのように着せ替えのモーフが多いモデルでは、ほとんどの材質が半透明の側に入るので、PMXに書かれた順で描かれます。不透明の側に残るのは、モーフの対象にならず、不透明度も1の材質(人物Aでは「顔00」「顔01」「首」など7つ)です。