5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

UnityのシーンをエクスポートしてThree.jsで使用する

Posted at

Unityで作成したシーンをエクスポートして、Three.jsで使用してみます。

手順は次のようになります。

  1. Unityでシーンを作成する
  2. FBX ExporterでFBXをエクスポートする
  3. FBX2glTFでFBXをglTFに変換する
  4. Three.jsでglTFを読み込む

UnityからエクスポートしたFBXを直接Three.jsで使用してもよいのですが、FBXよりもglTFの方が扱いが楽なのでglTFに変換しています。

この記事で使用するUnity、three.jsのバージョンは次のとおりです。

  • Unity: 2021.2.10f1
  • Three.js: r139

Unityでシーンを作成する

まず、エクスポートするシーンをUnityで作成します。今回は複数のメッシュとカメラを配置します。カメラにはアニメーションをつけておきます。エクスポート対象を一つのゲームオブジェクト(Root)にまとめておきます。
UnityScene.png
カメラアニメーションはこんな感じです。
UnityScene.gif

FBX ExporterでFBXをエクスポートする

UnityにFBX Exporterをインストールします。FBX ExporterはPackage ManagerのUnity Registryに存在しています。

FBX Exporterをインストール後、エクスポート対象をまとめたゲームオブジェクトを選択状態にしてMenu > GameObject > Export to FBX...をクリック(またはゲームオブジェクトを右クリックして、Export to FBX...をクリック)します。Export Optionsが表示されるので、次のように設定してExportボタンを押すと、指定したパスにFBXがエクスポートされます。
FbxExporterSetting.png

FBX2glTFでFBXをglTFに変換する

UnityからエクスポートしたFBXをFBX2glTFでglTFに変換します。

自分でビルドしてもいいですが、Releaseページから各OSごとにビルド済みの実行ファイルを取得することができるので、今回はこちらを使用します。

Macの場合はターミナルから次のようにglTFに変換します。FBX2glTFではdroco圧縮などの多数のオプションがありますが、今回は単純にバイナリ形式(GLB)に変換するだけにします。実行するとUnityToThreejs.glbが同じディレクトリに生成されます。

$ chmod +x ./FBX2glTF-darwin-x64 
$ ./FBX2glTF-darwin-x64 --binary ./UnityToThreejs.fbx 

Three.jsでglTFを読み込む

作成したglTFをThree.jsで読み込みます。読み込みにはGLTFLoaderを使用します。

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Unity to Three.js</title>
    <style>
      body {
        margin: 0;
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <script src="./lib/threejs/three.min.js"></script>
    <script src="./lib/threejs/examples/loaders/GLTFLoader.js"></script>
    <script>
      const renderer = new THREE.WebGLRenderer();
      renderer.setSize(window.innerWidth, window.innerHeight);
      renderer.setPixelRatio(window.devicePixelRatio);
      document.body.appendChild(renderer.domElement);

      const scene = new THREE.Scene();
      scene.background = new THREE.Color(0x999999);

      const dirLight = new THREE.DirectionalLight(0xffffff, 1.0);
      dirLight.position.set(-1.0, 3.0, -1.0);
      scene.add(dirLight);
      const ambLight = new THREE.AmbientLight(0x333333);
      scene.add(ambLight);

      let camera = null;
      let mixer = null;

      const loader = new THREE.GLTFLoader();
      loader.load('./assets/UnityToThreejs.glb', (gltf) => {
        // アニメーションの再生
        mixer = new THREE.AnimationMixer(gltf.scene);
        gltf.animations.forEach((animation) => {
          mixer.clipAction(animation).play();
        });

        const gltfCamera = gltf.cameras[0];
        camera = new THREE.PerspectiveCamera(
          gltfCamera.fov,
          window.innerWidth / window.innerHeight,
          // カメラのnearとfarはFBXに変換したときにセンチメートル単位になり、
          // FBX2glTFではメートルに変換してくれないので、ここでメートル単位に変換する
          gltfCamera.near * 0.01,
          gltfCamera.far * 0.01
        );
        // カメラアニメーションに存在する謎回転に対処するために、
        // 相殺する回転をかけてglTFカメラの子要素に追加する
        camera.rotation.set(0, -0.5 * Math.PI, 0);
        gltfCamera.add(camera);

        scene.add(gltf.scene);
      });


      function resize() {
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
      }
      window.addEventListener('resize', resize);

      const clock = new THREE.Clock();

      function animate() {
        requestAnimationFrame(animate);

        // アニメーションの更新
        if (mixer) {
          mixer.update(clock.getDelta());
        }

        if (camera) {
          renderer.render(scene, camera);
        }
      }
      animate();
    </script>
  </body>
</html>

カメラアニメーションがなぜかY軸に対して90度回転するので、glTFで読み込んだカメラを直接使わずに、回転を相殺するようにrotationを設定したカメラを子要素に追加して、そのカメラで描画するようにしています。
(カメラがY軸90度回転する問題はFBXを読み込んだときにも発生し、FBXの場合はアニメーションの有無に関わらず発生します。glTFの場合はアニメーションがなければ発生しません。おそらくFBX2glTFがアニメーションがない場合の回転は修正するが、アニメーションの回転は修正しないのではないかと思っています。)

Three.jsの描画は次のようになります。これでUnityのシーンをエクスポートしてThree.jsで描画することができました。
ThreejsScene.gif

比較

上がUnity、下がThree.jsの描画です。ライティングやマテリアルなどの違いがあるので全く同じようには描画できていませんが、モデルの配置やカメラワークは同じようにすることができました。
UnityScene.gif
ThreejsScene.gif

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?