投稿日:2024-06-18
#Rhinoceros
#Three.js
#R3F
今回は Rhinoceros と Web を連携させて、Web 側で Rhino モデルを編集し Rhino 側に反映させる方法について書いていきます。コードの解説は詳しくしませんが全体的な流れを説明していきます。詳しいコードにご興味ある方は、GitHub リポジトリを覗いてみてください。
動作状況 Youtube にアップしてますので動作状況確認したい方は以下のリンクからどうぞ!
上の画像が全体の流れになります。
といった感じになります。
最も重要なのは Rhino 側で付与したオブジェクトの id を Web 側に持っていくことです。これができてしまえば,後は各々色んなことができるかなといったところです。id の紐付けをするために userText を保持したままモデルを Export する必要があり、それについては以下の記事で書いてます。またプラグインも公開してるのでご興味あればリンク覗いてみてください(※テスト書いてないのでまだ β です)。今回はそれによってできること 1 のつの例として Web 側で Rhino モデルに変更を加えてみた、といったところです。 今回はモデル内の任意のオブジェクトの移動と、割り当てた userText の編集を Web 側で行なっています。
概要ではストレージや DB などと記載しましたが、 DB の構築もめんどくさかったので、ストレージはローカルの任意のフォルダとし、フロントから直接モデルの URL を参照しています。Web での変更内容は DB に保存するのではなく JSON ファイルに書き込んで、その JSON ファイルを Rhino 側から読み込むようにしました。
まず Rhino モデルの各オブジェクトに id を振っていきます。以下の python スクリプトで、選択した全てのオブジェクトの id を取得し、それを各オブジェクトの userText に key に id, value に取得した id の形式で格納します。
assign_existing_objid_to_objects.py
1import rhinoscriptsyntax as rs 2def assign_existing_objid_to_objects(): 3 objs = rs.GetObjects("Select objects to assign existing objId", preselect=True) 4 if not objs: 5 print("No objects selected.") 6 return 7 for obj in objs: 8 obj 9 rs.SetUserText(obj, "id", obj) 10 print(f"Assigned existing objId {obj} to object {obj}") 11assign_existing_objid_to_objects()
また今回は web 側で各オブジェクトに割り当てた userText も編集していきたいので、Rhino の画面からユーザーテキスト=>テキストフィールドで、適当に ObjectLayer を割り当てておきます。
これで、全てのオブジェクトに一意の id と ObjectLayer が UserText 内に格納されている状態となります。
次に UserText を割り当てた状態の Rhino モデルを glb でエクスポートしていきます。画像左側の model.glb が今回 Export したモデルです。Rhino 8では glb / gltf 形式でのエクポートが対応していますが、userText を保持したままの Export は対応していないので、概要で紹介した、以前作成したプラグインを使用して Export しました。 最初の概要で説明した手順だと、クラウドストレージにアップロードするようになってますが、今回は簡略化のためにローカルのデスクトップに sync というフォルダを作ってそこに保存します。もしクラウドに対して行いたい場合はクラウドへのアップロードとその URL を DB に保存する API を作成し、その API に対して Rhino 側から http リクエストを送れば良いかなと思います。
また、モデルの容量が重たい場合は Draco 圧縮をかけてメッシュの容量を大幅に削減できます。色々なツールがありますが、
は userText がロストすることなく Draco 圧縮かけることができたので必要であれば試してみてください。以前私も
を書いたのでご興味あればリポジトリを覗いてみてください。
Export した Rhino モデルの URL を参照してモデルをロードします。 もしクラウドに保存する場合は DB にクラウドのモデルを保存した URL を DB に格納して、その URL を参照する感じになると思います。
Web アプリ部分のコードは詳しく説明しませんが、ご興味あれば
を覗いてみてください。
アプリの機能としては、
となっています。
実際に変更を加えます。
変更内容の保存に関しては 以下のようなコードになっており、Next.js の API Routes を使用して API を作成し、変更内容を JSON でローカルフォルダに保存する処理を行なってます。
route.ts
1import { NextRequest, NextResponse } from "next/server"; 2import fs from "fs"; 3 4export async function POST(request: NextRequest) { 5 const data = await request.json(); 6 const filePath = "C:\\Users\\81803\\Desktop\\sync\\data.json"; 7 8 try { 9 fs.writeFileSync(filePath, JSON.stringify(data, null, 2)); 10 return NextResponse.json({ message: "File saved successfully" }); 11 } catch (err) { 12 console.error("Error writing file:", err); 13 return NextResponse.json({ error: "Failed to save file" }, { status: 500 }); 14 } 15}
data.json
1[ 2 { 3 "meshId": "46a2eba9-bde2-4a25-ab73-5975b59c4771", 4 "moveVector": { 5 "x": 0, 6 "y": 0, 7 "z": -8.965669279984013 8 } 9 }, 10 { 11 "meshId": "9cc784c1-d41f-4c74-8f63-5b2736338a4f", 12 "moveVector": { 13 "x": 16.945625117365523, 14 "y": 0, 15 "z": 0 16 } 17 }, 18 { 19 "meshId": "28d41bf8-fe0f-497f-9763-59a5612e1b84", 20 "moveVector": { 21 "x": 0, 22 "y": 0, 23 "z": -11.752210701921893 24 }, 25 "userText": { 26 "key": "ObjectLayer", 27 "value": "sleeve-wall-update!!!!" 28 } 29 } 30]
Rhino 側から Web 側での変更内容を取得していきます。先ほどローカルに保存した JSON を以下のコードで読み込んでいき、変更内容を反映させていきます。meshId から Rhino 上の対象のオブジェクトを取得して、そのオブジェクトに対して移動と userText の変更内容を反映させています。また、Rhinoceros では z 軸が上方向ですが、Three.js では y-up となっているので以下のようなコードになってます。
sync.py
1import rhinoscriptsyntax as rs 2import json 3def load_and_modify_objects(json_path): 4 with open(json_path, 'r') as file: 5 data = json.load(file) 6 for item in data: 7 mesh_id = item['meshId'] 8 obj = rs.coerceguid(mesh_id) 9 if obj: 10 if 'moveVector' in item: 11 move_vector = item['moveVector'] 12 move_x = move_vector['x'] * 1000 13 move_y = move_vector['z'] * -1000 14 move_z = move_vector['y'] * 1000 15 rs.MoveObject(obj, [move_x, move_y, move_z]) 16 if 'userText' in item: 17 user_text = item['userText'] 18 key = user_text['key'] 19 value = user_text['value'] 20 rs.SetUserText(obj, key, value) 21 else: 22 print(f"Object with meshId {mesh_id} not found.") 23json_path = "C:\\Users\\81803\\Desktop\\sync\\data.json" 24load_and_modify_objects(json_path)
もし ローカルの JSON ではなく、DB に保存している場合は、保存した内容を DB から取得する API を作成し、python の urllib など使用してリクエストを送れば良いかと思います。
Rhino 側に変更を反映させたら、そのモデルを再度 glb にしてアップロードします。 これで Web 側も新しく変更が加わった glb ファイルを参照することになるので、Web 側にも反映されます。
以上になります。ざっくりとした説明でしたが以上が全体の流れになります。 今回はオブジェクトの移動と UserText の編集でしたが、Web 側での処理を Rhino 側での処理にパースできるような処理であれば、編集だけでなく追加も可能だと思います。また履歴を残しておいて過去のモデルに戻るとか色々できるかと思います。最も重要なのは id の紐付けなので、今回は id の紐付けができたことによってこんなこともできるよという一例でした。
以上