[Three.js] transparent再入門


はじめに

three.jsの透過オブジェクトは、設定値が絡みあって複雑な挙動をします。これらの設定と挙動の関係を検証するために、デモページを作成しました。このデモページで製作上陥りがちな問題を再現し、その原因と解決策を確認します。

対象とする環境

▼package.json

"three": "0.105.2"

three.jsのバージョンが異なる場合、この記事の内容は適用できない場合があります。ご注意ください。

対象とする読者

この記事では、すでにthree.jsを利用している方を読者として想定しています。
インストールガイドやシーン、オブジェクトの初期化方法などは省略します。

デモページ

作成したデモページはこちらから。

上図のような画面が表示されます。左側のcanvas内をドラッグすることでカメラが移動します。右側が各種設定値を変更するコントローラーです。

初期状態では、以下のオブジェクトが表示されています。

  • 中央にはouterメッシュが表示されています。
  • その周りに配置されたsatelliteメッシュが表示されています。
  • このふたつの球体はそれぞれ透過しています。

デモページで発生する問題

このデモページでは、以下の問題が発生しました。それぞれ確認と解決をおこないます。

  1. メッシュの透過失敗
  2. 内包されたメッシュの描画失敗

問題1 : メッシュの透過失敗

デフォルトの状態のまま、カメラを移動していくと下図のようになります。

透過処理に失敗し、半透明の球体の裏側に入ったsatelliteメッシュが欠けています。

原因

この描画ミスの原因は、satelliteメッシュの座標の初期化方法にあります。

const geo = new SphereGeometry(5, 64, 64);
const mat = new MeshPhongMaterial({
    transparent: true,
    opacity: 0.5,
    color: new Color(color)
});
this.satellite = new Mesh(geo, mat);
this.satellite.geometry.translate(30, 0, 0);
                        ^^^^^^^^^
scene.add(this.satellite);

satelliteメッシュのジオメトリを変形して、画面中心から移動させています。
satellite.position.set(30,0,0)と座標は同じになりますが、深度処理の結果が異なります。

想定している状況

OBJLoaderなどの外部モデルデータのLoaderを利用すると、この状態が発生します。
Loaderから読み込んだオブジェクトは、position(0,0,0)を原点とするObject3Dに格納されていることがあります。その場合各パーツの座標はジオメトリに直接書き込まれています。この状態で直接Sceneに複数のモデルを追加すると、この問題が起きます。

解決方法

ジオメトリではなくメッシュの座標を変更すると、この問題は解決します。

デモページでは、コントローラーのsatelliteタブにあるチェックボックスをONにすると、下記のコードでsatelliteメッシュを再生成します。

const geo = new SphereGeometry(5, 64, 64);
const mat = new MeshPhongMaterial({
    transparent: true,
    opacity: 0.5,
    color: new Color(color)
});
this.satellite = new Mesh(geo, mat);
this.satellite.position.x = 30;
               ^^^^^^^^^
scene.add(this.satellite);


無事球体の裏側が描画されました。

問題2 : 内包されたメッシュの描画失敗

コントローラーのInner Sphereのx値を5に変更し、少しカメラを回転させてください。透過したouterメッシュの内側にinnerメッシュが突如描画されます。


この状態では、innerメッシュはouterメッシュに内包されています。

原因

この問題はWebGLのdepthTestという機能に起因します。

wgld.org : カリングと深度テスト

この時WebGLがどのような処理を行なっているのか、デモページの実験結果から読み解いてみます。

前提 : GPUの描画処理

まず、GPUがどのように高速描画を行なっているかを大まかに把握しておく必要があります。こちらの動画がGPUの特性をわかりやすく説明しています。