STUDIO TAMA


thumbnail

投稿日:2024-06-18

【Rhinoceros-Three.js】Synchronizing Rhinoceros with the WebApp

  • #Rhinoceros

  • #Three.js

  • #R3F

今回は Rhinoceros と Web を連携させて、Web 側で Rhino モデルを編集し Rhino 側に反映させる方法について書いていきます。コードの解説は詳しくしませんが全体的な流れを説明していきます。詳しいコードにご興味ある方は、GitHub リポジトリを覗いてみてください。

動作状況 Youtube にアップしてますので動作状況確認したい方は以下のリンクからどうぞ!

概要

thumbnail

上の画像が全体の流れになります。

  1. Rhinoceros の各オブジェクトに対して userText に id を格納。
  2. 格納した userText を保持した状態で Rhino モデルを glb/gltf でエクスポート(← これについては以前プラグインを開発し記事にしましたので以下のリンクの記事を参照ください)
  3. (※必要であれば) データの容量が重たいようであれば Draco 圧縮をかける
  4. export した glb モデルをアップロードしクラウドストレージ等に保存・保存先の URL を DB に保存
  5. DB に保存された URL を参照して Web 側でモデルをロード
  6. Web 側でモデルに変更を加える
  7. 変更した内容を、変更を加えたオブジェクトの id と内容とともに DB に保存
  8. Rhino 側から DB に格納された変更内容を取得
  9. 変更内容を Rhino 側のスクリプトにパースし変更を反映
  10. モデルに変更を反映させたら、手順2に戻り変更したモデルを再度アップロード、Web 側にも反映

といった感じになります。

最も重要なのは Rhino 側で付与したオブジェクトの id を Web 側に持っていくことです。これができてしまえば,後は各々色んなことができるかなといったところです。id の紐付けをするために userText を保持したままモデルを Export する必要があり、それについては以下の記事で書いてます。またプラグインも公開してるのでご興味あればリンク覗いてみてください(※テスト書いてないのでまだ β です)。今回はそれによってできること 1 のつの例として Web 側で Rhino モデルに変更を加えてみた、といったところです。 今回はモデル内の任意のオブジェクトの移動と、割り当てた userText の編集を Web 側で行なっています。

thumbnail

【Rhinoceros-plugin C#】Exporting Rhino Geometries with Attributes User Text to GLB/GLTF

Rhinocerosで作成したモデルをUserTextを持たせたままWebで表示する

主要な使用ツール

  • Rhinoceros ver8 (7 でも問題ない)
  • Next.js 14.2.4 (フロント + API)
  • Three.js 0.165.0 + React three fiber8.16.8 (WebGL)

概要ではストレージや DB などと記載しましたが、 DB の構築もめんどくさかったので、ストレージはローカルの任意のフォルダとし、フロントから直接モデルの URL を参照しています。Web での変更内容は DB に保存するのではなく JSON ファイルに書き込んで、その JSON ファイルを Rhino 側から読み込むようにしました。

Rhino 側での準備

thumbnail

まず 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 内に格納されている状態となります。

Rhino モデルの Export

thumbnail

次に UserText を割り当てた状態の Rhino モデルを glb でエクスポートしていきます。画像左側の model.glb が今回 Export したモデルです。Rhino 8では glb / gltf 形式でのエクポートが対応していますが、userText を保持したままの Export は対応していないので、概要で紹介した、以前作成したプラグインを使用して Export しました。 最初の概要で説明した手順だと、クラウドストレージにアップロードするようになってますが、今回は簡略化のためにローカルのデスクトップに sync というフォルダを作ってそこに保存します。もしクラウドに対して行いたい場合はクラウドへのアップロードとその URL を DB に保存する API を作成し、その API に対して Rhino 側から http リクエストを送れば良いかなと思います。

また、モデルの容量が重たい場合は Draco 圧縮をかけてメッシュの容量を大幅に削減できます。色々なツールがありますが、

gltf-pipeline

は userText がロストすることなく Draco 圧縮かけることができたので必要であれば試してみてください。以前私も

を書いたのでご興味あればリポジトリを覗いてみてください。

web で表示

thumbnail

Export した Rhino モデルの URL を参照してモデルをロードします。 もしクラウドに保存する場合は DB にクラウドのモデルを保存した URL を DB に格納して、その URL を参照する感じになると思います。

Web アプリ部分のコードは詳しく説明しませんが、ご興味あれば

を覗いてみてください。

アプリの機能としては、

  1. モデルのロード
  2. 各オブジェクトの移動
  3. Rhino 側で格納した各オブジェクトの UserText の情報の表示・編集
  4. オブジェクトに対して行なった変更内容を保存

となっています。

web でモデルを変更し変更内容を JSON で Export

thumbnail

実際に変更を加えます。

  1. 上画像のようにいくつかのオブジェクトを移動させます
  2. 画面右側のフォームからオブジェクトに格納されている UserText を 1 つ編集してみます
  3. 変更が完了したら画面右下の青いボタンを押して変更内容を保存します

変更内容の保存に関しては 以下のようなコードになっており、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}
  1. 保存された変更内容は以下のような形式で保存しています。meshId には変更を加えたオブジェクトの id を、オブジェクトを移動させた場合は moveVector に移動させたベクトルを、userText を編集した場合は userText に変更した内容を key, value で保存しています。

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]

Web での変更内容を Rhino 側に反映

thumbnail

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 側の変更を再度 Web 側に反映

Rhino 側に変更を反映させたら、そのモデルを再度 glb にしてアップロードします。 これで Web 側も新しく変更が加わった glb ファイルを参照することになるので、Web 側にも反映されます。

終わり

以上になります。ざっくりとした説明でしたが以上が全体の流れになります。 今回はオブジェクトの移動と UserText の編集でしたが、Web 側での処理を Rhino 側での処理にパースできるような処理であれば、編集だけでなく追加も可能だと思います。また履歴を残しておいて過去のモデルに戻るとか色々できるかと思います。最も重要なのは id の紐付けなので、今回は id の紐付けができたことによってこんなこともできるよという一例でした。

以上

目 次