7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Elixirで直接VRを操作する 〜 ResoniteLink 〜

Last updated at Posted at 2026-01-12

ResoniteにResonite Linkが実装されたので検証しました

Resonite Linkとは

WebSocketを使ってResoniteを操作することができます

下記の例はBoxを作っています

Resonite Linkは2026/1/13時点ではベータリリースです
今後仕様が変わる可能性はあります

Resonite Linkの有効化

セッション > Resoniteリンクを有効化 をクリックしてください
image.png

Resoniteリンクを有効化するとポートナンバーが表示されます
この例では39593になります
image.png

ポートナンバーは毎回変化します

コードを書く

websockexを使います

mix.exs
defmodule ResoniteRedRect.MixProject do
  use Mix.Project
# 省略
  defp deps do
    [
+     {:websockex, "~> 0.4.3"}
    ]
  end
  # 省略
end

Boxを作るソース

lib/rect01.ex
defmodule Rect01 do
  use WebSockex
  require Logger

  @port 39593
  @host "127.0.0.1"

  def start_link(_opts \\ []) do
    WebSockex.start_link("ws://#{@host}:#{@port}", __MODULE__, :no_state,
      extra_headers: [
        {"Host", "#{@host}:#{@port}"}
      ]
    )
  end

  def handle_connect(_conn, state) do
    Logger.info("ResoniteLinkに接続成功!")
    {:ok, state}
  end

  def start() do
    {:ok, pid} = start_link()
    add_slot(pid)
    add_box_mesh(pid)
    add_pbs_metallic(pid)
    add_mesh_renderer(pid)
    update_mesh_renderer(pid)
    update_mesh_renderer(pid)
  end

  def send_text(msg, pid) do
    WebSockex.cast(pid, {:send_text, msg})
    #Process.sleep(1000)
  end

  def add_slot(pid) do
    """
    {
      "$type" : "addSlot",
      "data" : {
          "id" : "ymn_1",
          "parent" : {
              "$type" : "reference",
              "targetId" : "Root"
          },
          "name" : {
              "$type" : "string",
              "value" : "YMN_Box"
          },
          "position" : {
              "$type" : "float3",
              "value" : {
                  "x" : 0,
                  "y" : 1.5,
                  "z" : 10
              }
          }
      }
    }
    """
    |> send_text(pid)
  end

  def add_box_mesh(pid) do
    """
    {
      "$type" : "addComponent",
      "containerSlotId" : "ymn_1",
      "data" : {
          "id" : "ymn_2",
          "componentType" : "[FrooxEngine]FrooxEngine.BoxMesh"
      }
    }
    """
    |> send_text(pid)
  end

  def add_pbs_metallic(pid) do
    """
    {
        "$type" : "addComponent",
        "containerSlotId" : "ymn_1",
        "data" : {
            "id" : "ymn_3",
            "componentType" : "[FrooxEngine]FrooxEngine.PBS_Metallic"
        }
    }
    """
    |> send_text(pid)
  end

  def add_mesh_renderer(pid) do
    """
    {
        "$type" : "addComponent",
        "containerSlotId" : "ymn_1",
        "data" : {
            "id" : "ymn_4",
            "componentType" : "[FrooxEngine]FrooxEngine.MeshRenderer",
            "members": {
                "Mesh": {
                    "$type": "reference",
                    "targetId": "ymn_2"
                }
            }
        }
    }
    """
    |> send_text(pid)
  end

  def update_mesh_renderer(pid) do
    """
    {
        "$type" : "updateComponent",
        "data" : {
            "id" : "ymn_4",
            "members" : {
                "Materials": {
                    "$type": "list",
                    "elements": [
                        {
                            "$type": "reference",
                            "targetId": "ymn_3"
                        }
                    ]
                }
            }
        }
    }
    """
    |> send_text(pid)
  end

  # キャスト(非同期送信)の処理
  def handle_cast({:send_text, msg}, state) do
    {:reply, {:text, msg}, state}
  end

  def handle_frame({:text, msg}, state) do
    Logger.info("受信データ: #{msg}")
    {:ok, state}
  end
end

コード説明

  • @port 39593

    • Resonite Linkの有効化時のナンバーを書く
  • @host "127.0.0.1"

    • Resoniteの起動したアドレスを書く
  • def start_link

    • WebSocketでResoniteに接続する
  • def handle_connect

    • 接続が成功するとこの関数が呼ばれる
  • def start

    • 実際に実行する為の関数
  • def send_text

    • Resoniteに送信する関数
  • def add_slot

    • Resoniteにスロットを追加する
    • $type" : "addSlot"はスロットを追加コマンド
    • "id" : "ymn_1"はこのResonite Linkの有効化時のみ有効なID
      • 今後出てくるIDを同様の意味になります
      • 一旦Resonite Linkが切れるとIDは再使用できません
        • このサンプルではIDを取得する方法は書きません
          • 手間がかかるので省略
    • |> send_text(pid)
      • Resoniteに送信
      • pidはstart_link()時のpidを使う
  • def add_box_mesh

    • この関数はBoxMesh(長方形)コンポーネントを追加
    • $type" : "addComponent"はコンポーネントを追加コマンド
    • "containerSlotId" : "ymn_1"
      • スロットのIDを定義します
    • "componentType" : "[FrooxEngine]FrooxEngine.BoxMesh"
      • コンポーネントの種類を定義
      • ここではBoxMeshを定義
  • def add_pbs_metallic

    • PBS_Metallic(色)コンポーネントを追加
  • def add_mesh_renderer

    • MeshRendererコンポーネントを追加
    • membersのMeshでBoxMeshと定義
      • add_box_meshで作ったID ymn_2をtargetIdにする
  • def update_mesh_renderer

    • MeshRendererコンポーネントの内容を更新する関数です
    • $type" : "updateComponent"はコンポーネントを更新するコマンド
    • membersのMaterialsでPBS_Metallicと定義

実行方法

ライブラリ取得

$ mix deps.get

iex起動

$ iex -S mix

iex上で実行

iex(1)> Rect01.start()

補足 ResoniteでBoxを作る為の知識

前提 スロットの中にコンポーネントを入れます

今回の例は

  • スロット
    • BoxMeshコンポーネント
    • PBS_Metallicコンポーネント
    • MeshRendererコンポーネント
      • BoxMesh関連付け
      • PBS_Metallic関連付け

このような構成になります

ハマりポイント

MeshRendererコンポーネントでPBS_Metallicは2回定義しない動作しませんでした
原因はまだ把握してません
知っていたらコメントお願いします

ソース

7
1
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
7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?