投稿日:2023-10-09
#Grasshopper
#Python
#Three.js
#R3F
今回は Grasshopper で生成したモデルをブラウザで表示し、Grasshopper での変更をリアルタイムでブラウザにも反映させていく方法について書いていきます。(※リアルタイムといってもブラウザのリロードは必要です。)
今回はローカルで行いますが、クラウドでも実装可能だと思うので、モデルの閲覧だけならブラウザでチーム共有するみたいなこともできるかと思います。
トップにある画像が全体の流れになります。
step4 の Draco 圧縮は Node.js を使って行ってますが、food4Rhino の以下のアドオンを使用すれば step2 で fbx で出力せず、そのまま Draco 圧縮をかけたモデルを出力できます。
しかし、非推奨になってしまっていたので今回は使用しませんでした。(いちおまだ使うことはできるようです。)
上記が Grasshopper のプログラム全体像になってます。
3グループに分かれてますが 1 グループ目はモデルを生成してます。ここは何でもよくて最終的に Brep で出力されてれば OK です。それぞれお好きなモデルで実装してみてください。私は以前記事で書いた以下のモデルを使用します。
作成した Mesh を fbx 形式で Export していきます。プラグイン
を使用しています、インストールしてない方はインストールお願いします。
1import rhinoscriptsyntax as rs 2import Rhino 3import scriptcontext as sc 4sc.doc = Rhino.RhinoDoc.ActiveDoc 5 6output_folder = "C:\\Users\\81803\\Desktop\\outpuFolder\\" 7obj_name = "voronoiSphere" 8object_file_name = "{}.fbx".format(obj_name) 9file_path = output_folder + object_file_name 10 11if baked != None: 12 ids = rs.ObjectsByLayer(layer_name) 13 selected_objects = rs.SelectObjects(ids) 14 rs.Command("_-SaveAs {} _Enter".format(file_path)) 15 rs.UnselectAllObjects() 16 finish_export = "finish"
Node.js を使用して先ほど出力した fbx 形式のモデルを Draco 圧縮していきます。
モデルの容量が大きくない場合は圧縮する必要はないかもしれませんが、ある程度容量が大きくなるとブラウザでのロード時間が長くなってしまいます。
ある程度容量の大きなモデルを想定して圧縮処理を加えていきます。今回は Node.js を使用して圧縮をかけていきますが、Node.js 自体の解説は詳しくしていきません。ご自身のお得意な言語で実装して見てください。
また冒頭でも述べましたが、より簡単な方法は
のアドオンを使用すると Rhinoceros 上で Draco 圧縮されたファイルを Export できるので、事前に Draco 圧縮する設定をしておき、step2 で.fbx で出力するところを.gltf で出力すればこの Node.js を使用せずとも Draco 圧縮できます。まだダウンロードできますが、DEPRECATED になっているのでご注意ください。
以下が Node.js で作成した圧縮処理になります、フレームワークは Express を使用してます。すべてのコードを確認したい方は
をのぞいてみてください。
1import { Router } from "express"; 2import fsExtra from "fs-extra"; 3const convert = require("fbx2gltf"); 4const compress = require("gltf-pipeline"); 5 6const router = Router(); 7 8router.post("/", async (req, res) => { 9 const { path, fileName }: { path: string, fileName: string } = req.body; 10 11 //fbx => glb 12 const inputPath = path + fileName + ".fbx"; 13 const outputPath = `${path + fileName}.glb`; 14 await convert(inputPath, outputPath); 15 16 // gltfPipeline glb => gltf 17 const inputGlbFilePath = outputPath; 18 const outputGlbFilePath = `${path + fileName}_converted.gltf`; 19 const glbToGltf = compress.glbToGltf; 20 const glb = fsExtra.readFileSync(inputGlbFilePath); 21 await glbToGltf(glb).then(function (results: any) { 22 fsExtra.writeJsonSync(outputGlbFilePath, results.gltf); 23 }); 24 25 // gltfPipeline gltf => draco_compress 26 const processGltf = compress.processGltf; 27 const inputCompressFilePath = outputGlbFilePath; 28 const compressFilePath = `\\outputのpath\\${fileName}_compress.gltf`; 29 30 const gltf = fsExtra.readJsonSync(inputCompressFilePath); 31 const options = { 32 dracoOptions: { 33 compressionLevel: 10, 34 }, 35 }; 36 37 await processGltf(gltf, options).then(function (results: any) { 38 fsExtra.writeJsonSync(compressFilePath, results.gltf); 39 }); 40 41 res.status(200).json("compression_finished"); 42}); 43 44export default router;
これで Draco 圧縮するための API 完成です。
ちなみに今回のモデルを圧縮すると、以下のようになります。もともと 1.58Mb なので圧縮する必要ないのですが、1.58Mb => 338kb まで圧縮できました。
前項で作成したエンドポイントに対して、Ghpython からリクエストを送ります。github リポジトリは
先ほど作成した Ghpython コンポーネントに追記していきます。
1import urllib2 2import json 3import rhinoscriptsyntax as rs 4import Rhino 5import scriptcontext as sc 6sc.doc = Rhino.RhinoDoc.ActiveDoc 7 8output_folder = "C:\\Users\\81803\\Desktop\\outputFolder\\" 9obj_name = "voronoiSphere" 10object_file_name = "{}.fbx".format(obj_name) 11file_path = output_folder + object_file_name 12 13def compression(): 14 url = 'http://localhost:3001/api/compression' 15 sendValues = { 16 'path':output_folder, 17 'fileName':obj_name 18 } 19 20 sendValuesJson = json.dumps(sendValues).encode("utf8") 21 request = urllib2.Request(url,sendValuesJson) 22 request.add_header("Content-Type",'application/json') 23 request.get_method = lambda: 'POST' 24 response = json.load(urllib2.urlopen(request)) 25 print response 26 27if baked != None: 28 ids = rs.ObjectsByLayer(layer_name) 29 selected_objects = rs.SelectObjects(ids) 30 rs.Command("_-SaveAs {} _Enter _Enter".format(file_path)) 31 rs.UnselectAllObjects() 32 compression() 33 finish_export = "finish"
プロジェクトを立ち上げて Draco 圧縮したモデルを表示していきます。今回は React プロジェクトを立ち上げて、Three.js も React Three Fiber を使用しています。詳しい方法は過去の記事で解説してますので以下を参照してください。
プログラムの一部を解説していきます。プログラム全体は
参照願います。
1import "./App.css"; 2import * as THREE from "three"; 3import { Canvas } from "@react-three/fiber"; 4import { OrbitControls, Stage, useGLTF } from "@react-three/drei"; 5 6const material = new THREE.MeshStandardMaterial({ 7 vertexColors: true, 8}); 9 10function App() { 11 const modelPath = "/model/voronoiSphere_compress.gltf"; 12 const gltf2 = useGLTF(modelPath); 13 gltf2.scene.traverse((child) => { 14 if (child instanceof THREE.Mesh) { 15 child.material = material; 16 } 17 }); 18 19 return ( 20 <> 21 <Canvas 22 style={{ width: "100vw", height: "100vh", background: "#333" }} 23 camera={{ 24 fov: 75, 25 near: 0.1, 26 far: 20000, 27 position: [0, 20, 30], 28 }} 29 > 30 <OrbitControls makeDefault /> 31 <directionalLight intensity={1.15} /> 32 <axesHelper scale={200} /> 33 <Stage intensity={0.02} environment={"city"} adjustCamera={true}> 34 <primitive object={gltf2.scene} /> 35 </Stage> 36 </Canvas> 37 </> 38 ); 39} 40 41export default App;
これで完了です。
上の gif が実際に動かした際の様子になります。
以上
【参考】