今回は、Grasshopperで作成したRhinoを、React Three Fiber(Three.jsをReactを使用して実装できるライブラリ)を使ってWebブラウザで表示していきたいと思います。React Three Fiberを使用すると、Vanilla.jsで実装するよりもだいぶ楽にはなります。ただし、Vanilla.jsで実装できないと、かなりブラックボックスになってしまうのと、複雑なことをやろうとすると難しいことが多々出てきますのでその辺りは要注意です。ソースコードはGithubにアップしてます。
今回表示するモデル


今回ブラウザで表示するのは、以前GrasshopperとMonocerosというプラグインを使用して作成したモデルを使用します。作り方、ご興味あれば以下のリンクからのぞいてみてください。
こちらのデータはメッシュ化した後、joinして単一メッシュにしていおります。この状態で現状18MBあります。ブラウザに持っていくにはちょっと重たいですね。
このままではロード時間もかかってしまうので、まずはこちらのモデルを軽量化していきます。
Draco圧縮をかける

- ひとまずRhino上でできることは限られているので、モデルをBlenderに移行しましょう。Blenderはオープソースですので、誰でも無料で使用することができるソフトウェアとなっております。インストールはこちらからできます。
- まずはRhinocerosから、モデルをFBX形式でエクスポートします。

- Blenderにモデルをインポートします。Rhino上でメッシュをjoinしたので、右上のレイヤにはオブジェクトが1つしか格納されていませんが、もしjoinしてなくて大量のオブジェクトがある場合は、すべて選択しCtrl + Jでジョインすることをお勧めします。
- Draco圧縮という技術を使用してデータを軽量化していきます。Draco圧縮はGoogleが開発した圧縮方法で、WebGLをやられている方はよく使用するかと思います。BlenderではDraco圧縮したデータをエクスポートできます。(※本来であれば、Blender Pythonなどを使用して一括でメッシュ数を減らしたりするのですが、説明が長くなるので割愛します。もしご興味あれば、「モディファイア一括適用」などで調べてみてください。)

- glb形式でエクスポートするので、モデルを選択した状態で、ファイル⇒Export⇒glTF2.0を選択します。

- 上画像の様にcheckボックスにチェックを入れてください。
- includeはSelected Objects(選択したオブジェクトのみエクスポートする。)
- Transformは、Three.jsでは上方向はZ軸ではなくY軸なので、Y軸が上方向とするためにチェックを入れます。
- Geometryに関しては、今回はロードするだけですが、とりあえずUVs、Normalsをエクスポートしときます。Materialもエクスポートとしておきます。
- Compressionの欄ですが、ここにチェックを入れることでDraco圧縮されます。もし元々データが重くなければ、ここのチェックをはずし、Draco圧縮しないglbデータをエクスポートします。

- 3.4MB弱になりました。もう少し最適化すればもう1MBぐらい落ちそうですが、今回はよしとしましょう。Rhno上で18MBからスタートし、3.4MBなので悪くないかなと思います。
React Three Fiber(アプリの立ち上げ)

- React Three Fiberを実装していきます。Node.jsを事前にインスト-ルしておく必要があります。こちらからLTSバージョンをインストールしておいてください。(※最新版でもいいのですが、新しすぎるとバグなど残っていることもあるので、LTS推奨版をインストールすることをお勧めします)
- 今回はエディターはVSCodeを使用しております。プロジェクトを保存するディレクトリを開き、VSCodeのターミナルから以下の1行目を実行し、myappというアプリ名でReact アプリケーションを作成します。少し時間がかかります。(※ちなみにReactのバージョンは18.2です)
- その後、2行目のcd myappでアプリの階層に移動します。
- 3行目npm startでローカルサーバーを立ち上げます。おそらくデフォルトではPORT:3000で立ち上がるので、http://localhost:3000/にアクセスし、上画像の様にReactのアイコンがブラウザに表示されればOKです。
- 問題なければCtrl+Cでサーバーを止めましょう。
npx create-react-app myapp
cd myapp
npm start
- three.jsとreact three fiberをインスト-ルします。ターミナルで以下を実行してください。ちなみに今回私がインストールしたバージョンと合わせたい方は2行目を実行してください。
npm install three @react-three/fiber
npm install three@0.146 @react-three/fiber@8.9.1
- App.jsを以下の様に書き換えます。
import "./App.css";
import { Canvas } from "@react-three/fiber";
function App() {
return (
<>
<Canvas style={{ width: "100vw", height: "100vh" }}>
<mesh>
<sphereGeometry />
<meshNormalMaterial />
</mesh>
</Canvas>
</>
);
}
export default App;
- その後、サーバーを再度起動します。今度はnpm start devで起動します。これで再度サーバーを立ち上げることなく、コードを書き換えて保存すれば反映されます。

- 上画像の様に、球体が表示されればOKです。
React Three Fiber(モデルの表示)
- それでは作成したモデルを表示していきます。まずは、react-three/drei というライブラリをインストールしていきます。こちらは、React Three Fiberの実装を簡単にしてくれるモジュールを提供してくれる便利なライブラリとなっております。⇒ドキュメント
- Ctrl+Cでサーバーを止め、(※サーバーを止めずにターミナルをもう1つ立ち上げてもOK)以下を実行してインスト-ルします。
npm install @react-three/drei
- publicディレクトリにmodelディレクトリを作成し、blenderから掃き出したglbデータを格納します。
- App.jsを以下の様に書き換えます。
import "./App.css";
import { Canvas } from "@react-three/fiber";
import { useGLTF } from "@react-three/drei";
function App() {
const model = useGLTF("/model/pipe.glb");
return (
<>
<Canvas style={{ width: "100vw", height: "100vh" }}>
<primitive object={model.scene} />
</Canvas>
</>
);
}
export default App;

- サーバーを起動してブラウザを確認すると、上画像の様にモデルが表示されます。(※モデルのサイズによっては、カメラの位置との兼ね合いで映ってないかもですが。)
- Vanilla.jsで実装したことがある方ならわかるかと思いますが、React Three Fiberをつかうとかなり少ないコードで書けちゃいます。
- しかし、真っ黒ですね。原因は、MaterialはBlenderからエクスポートしたので割り当てられてはいるが、ライトがない。
- またカメラの位置を設定していないのでモデル全体が見えてない。といった感じです。
- とりあえずカメラの位置を調整します。カメラの座標を(0,5,10)に設定します。
- directionalLightを設け、光を当ててあげます。また、Canvasのbackgroundを#333と背景を暗くしています。
import "./App.css";
import { Canvas } from "@react-three/fiber";
import { useGLTF } from "@react-three/drei";
function App() {
const model = useGLTF("/model/pipe.glb");
return (
<>
<Canvas
style={{ width: "100vw", height: "100vh", background: "#333" }}
camera={{
fov: 75,
near: 0.1,
far: 200,
position: [0, 5, 10],
}}
>
<directionalLight position={[0, 10, 0]} intensity={1.0} />
<primitive object={model.scene} />
</Canvas>
</>
);
}
export default App;

- いい感じですね。次にOrbitContorolを設け、モデルを自由に見れるようにします。
import "./App.css";
import { Canvas } from "@react-three/fiber";
import { OrbitControls, useGLTF } from "@react-three/drei";
function App() {
const model = useGLTF("/model/pipe.glb");
return (
<>
<Canvas
style={{ width: "100vw", height: "100vh", background: "#333" }}
camera={{
fov: 75,
near: 0.1,
far: 200,
position: [0, 5, 10],
}}
>
<directionalLight position={[0, 10, 0]} intensity={1.0} />
<OrbitControls makeDefault />
<primitive object={model.scene} />
</Canvas>
</>
);
}
export default App;

- OrbitControlsを追加しました。これで、[0,0,0]中心にカメラを動かすことができます。
- これでモデルの表示が完了しましたが、もう少し手を加えていきます。
おまけ

import "./App.css";
import { Canvas } from "@react-three/fiber";
import { Environment, OrbitControls, useGLTF } from "@react-three/drei";
import * as THREE from "three";
function App() {
const model = useGLTF("/model/pipe.glb");
Object.keys(model.materials).forEach((key) => {
const material = model.materials[key];
material.roughness = 1.0;
material.color = new THREE.Color("#008b8b");
});
return (
<>
<Canvas
style={{ width: "100vw", height: "100vh", background: "#333" }}
camera={{
fov: 75,
near: 0.1,
far: 200,
position: [0, 5, 10],
}}
>
<Environment preset="sunset" />
<OrbitControls makeDefault />
<primitive object={model.scene} />
</Canvas>
</>
);
}
export default App;
- マテリアルの色を変更し、roughnessもマット感のある感じにしております。
- また、Diretional Lightではなく、dreiがモジュール化している環境光に変更しました。
以上になります。今回は、React Three Fibe使用しましたが、もちろん通常のThree.jsでも同じことができます。もしThree.jsに興味があれば、個人的にはThree.js journeyがおすすめです。javascriptの基礎は必要ですが、Three.jsの基本から、シェーダー、React three fiberまでサポートされてます。Typescriptのみサポートされていませんが、Typescriptは別で勉強すれば全く問題ないと思います。95ドルですが、かなりボリュームのある内容になっており、全然安いかなと個人的には思います。ご興味あればリンクから覗いてみてはいかがでしょうか。
【参考】
- Three.js Docs:https://threejs.org/docs
- React Drei Docs : https://github.com/pmndrs/drei