three.jsでMMDモデルの半透明はどう決まるか|材質の不透明度・モーフ・テクスチャの透明

半透明の材質は、不透明な材質を全部描いたあとに描かれ、後ろが透けて見えます。three.jsでMMDモデルを読むと、どの材質が半透明になるのかを、実物のモデルとMMDLoaderのソースで確かめました。

最終更新: 2026-10-07 · 実PMX 2体をこのサイトの再生(three.js r171 の MMDLoader)で読み込み、材質ごとの半透明の扱いと、テクスチャの透明な画素を使う三角形を数えた。描く順番は WebGLRenderer の並べ替えの関数で確認

半透明になる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つ)です。