29
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

NeosVR resoAdvent Calendar 2020

Day 11

NeosVR+Elixirで気軽にVR WebSocketプログラミング(VR |> AR投影アプリの裏側)

Last updated at Posted at 2020-12-11

この記事は「NeosVR reso Advent Calendar 2020」、および「NeosVR Advent Calendar 2020」の11日目です

昨日は、@nuwaa さんの「『NeosVR reso』というコミュニティ 」でした


NeosVRから現実世界に干渉し、生活や仕事をより良いものへと改変していくコミュニティ「NeosVR reso」のオーガナイザー、piacereです
ご覧いただいて、ありがとうございます :bow:

私は、分散・並列データサイエンスに強い「Elixir」というプログラミング言語を2015年から使い始め、2017年以降はコミュニティ「fukuoka.ex」を主催しつつ、業務でも積極登用してて、現在は業務/プライベート共に、ほぼこの言語しか使っていない状態なんですが、国内ではまだまだマイナーな部類の言語です

しかし、世界を見てみると、StackOverflowという有名サイトが行った「世界でもっとも高給取りなプログラミング言語ランキング」で5位に入っている言語で、更にDiscordやSlack、Spotifyをはじめとする世界的サービスでも使われてるんです

StackOverflow
https://insights.stackoverflow.com/survey/2019#top-paying-technologies

上記資料の日本語紹介
https://news.mynavi.jp/article/20190415-807198/

今回、このElixirとNeosVRを繋いで、気軽にVR WebSocketプログラミングをしてみます

内容が、面白かったり、役に立ったら、「LGTM」よろしくお願いします :wink:

:ocean::ocean::ocean: お知らせ:NeosVR reso Advent Calendar、2位達成ヽ(=´▽`=)ノ :ocean::ocean::ocean:

今年初登場のNeosVR reso Advent Calendar、Webテクノロジーカテゴリで2位獲得です:tada:
https://qiita.com/advent-calendar/2020/neosvr_reso
image.png

なお、「NeosVR |> AR投影アプリ」で使っているElixirも、プログラミング言語カテゴリで2位でした:laughing:
https://qiita.com/advent-calendar/2020/elixir
image.png

NeosVR |> WebSocket |> Elixirで何ができるの?

その1例として、NeosVR内のオブジェクト情報を、ARアプリに配信し、現実世界と重ね合わせる投影が可能になります

NeosVRとElixirの悪魔合体でVRと現実世界が繋げられる

NeosVRの良いところ

NeosVRは、LogiXというプログラミングツールを使って、HTTP GET/POSTやWebSocketをVR内でプログラミングできるため、NeosVRの外にあるAPIや、WebSocket対応しているシステムもしくは機器とカンタンに接続できます

これを使うと、NeosVRから様々な現実のサービスやインフラを利用したり、NeosVR内で起こったことや行ったアクションを現実世界に反映させたり、NeosVRで見ているVR風景を現実に投影させるといったことが可能です

更に、WebSocketであれば、現実で起こった出来事をセンサーやIoTで拾い、NeosVRの中に送り込んで処理することもできるので、現実で誰かが見ている風景をVR内で複数人で同時共有したり、MIDI楽器を打鍵したらNeosVR内で音として鳴らしてみんなで聞く、といったことも可能です

ただしLogiXは、ノードプログラミングであるため、データ処理や演算、認証処理といったインフラ構築やWebサービス開発で頻出するロジック開発にはあまり向いていないので、複雑な処理を行いたい場合は、外部にサーバを立てて、ラップさせた方がラクできます

Elixirの良いところ

Elixirは、DB接続するAPI開発(REST API)のような、現実のサービスやインフラを作ることが、コマンド1発で出来ますし、WebSocket開発も、「Channel」という機能を使えば、接続確認やサーバ構築といった、面倒なことを一切スッ飛ばし、受け取りたいデータ/流したいデータのことだけを考えて作れるので、一瞬で開発が完了します

更に、JSONやバイナリデータのハンドリング(パース、パターンマッチングによるデータ内容次第での処理分岐)や、それらデータそのものの加工や集計がメチャクチャ強いのも、データサイエンスに強いElixirならではの特徴です

そのため、他サービス/機器のAPIやWebSocketをラップし、Elixirで適切なデータ加工/集計を行うことで、NeosVRと他サービス/機器を繋ぐ際、そのどちらにも最適なデータ交換を提供できます

また、このラップ構成にした場合、DiscordやSlack、Spotifyでやっているような、大量アクセスを処理する負荷分散構成に近くなり、「リクエストの受付」と「本体処理」を分離できるようにもなるため、ユーザ急増やサービスグロースといった「嬉しい悲鳴」が起こっても、性能改善に追われたり、高額なクラウド費用を支払うこと無く、安全にスケールアウトしていくことができます

そんな2つを悪魔合体させるとどうなる?

端的に言えば、「VR空間」と「現実世界」を、超絶お手軽に繋げられるようになります

それによる恩恵は、今月後半のAdvent Calendarに詳しく書くので、ココではざっくり解説ですが、以下のような世界観が叶います

  • 「VR」 → 「現実(+IoT)」 → 「VR」
  • VRで起こるイベントや起こすアクションで現実にIoTなど経由で干渉し、その結果をセンシングして、VR改変を行う
  • 「現実(+IoT)」 → 「VR+AI・ML」 → 「現実(+AR)」
  • 現実で起こるイベントや起こすアクションをVR+AI・ML内で処理し、その結果に基づいて、サイネージや3Dプリンタなどによって現実改変を行う

これはまさに「Society 5.0」もしくは「インダストリー 4.0」の世界観ですね

Society 5.0 - 科学技術政策 - 内閣府
https://www8.cao.go.jp/cstp/society5_0/
image.png

インダストリー 4.0とは
https://seizo-net.com/industry40/
image.png

実際、どのような活用方法があるかは、下記コラムをご覧ください

「NeosVR |> AR投影アプリ」が拓く生活と仕事:人はより「現実」へと出ていき、世界が変わったことを理解する
https://qiita.com/piacerex/items/fcb29251e37b1ac3e063

その先に、どのような世界観があるかは、下記コラムをご覧ください

NeosVRに見出した可能性と未来について:「4つの世界」は「7つの世界」に
https://qiita.com/piacerex/items/7c29778e19e5b281f293

NeosVR+ElixirでVR WebSocketプログラミング

それでは、これら構想(妄想?)の基本となる、NeosVR+ElixirによるVR WebSocketプログラミングを行っていきましょう

まず、NeosVR側のWebSocket送信について、LogiXプログラミング解説を行い、その後、ElixirでのWebSocketサーバ構築の解説をします

NeosVR側の全体像

NeosVR側では、NeosVRオブジェクトの属性を取得して、それをJSON化し、WebSocket送信しています

その全体像は、こんな感じです
image.png

思ったよりもロジックが少ないように見えますが、それは「BluePrint」というモジュール化を行うツールの影響です

ここから、各モジュールの中身を見ていきます

①:個々のオブジェクト属性をオブジェクト名付きJSON化する

オブジェクト属性を拾い出し、JSON化し、オブジェクト名を付与するところまでを「ObjectJsoner」で行っていて、中身は、「ObjectDecomposerOnChanged」と「XYZJSONBuilder」、「XYZWJSONBuilder」、「JSONBuilder」、「ObjectJSONBinder」で構成されています
image.png

①-1:オブジェクト属性のJSON化

最初は「ObjectDecomposerOnChanged」ですが、これはオブジェクトのPosition/Rotation/Scaleのいずれかに変化があった場合、Trueを返しつつ、変化があった場合のJSON構築のためのPosition/Rotation/Scaleの値を次に流しています
image.png

JSON構築のためのPosition/Scaleなどの3値は、「Float3UpdateChecker」で、前回変化時とのFloat3の比較を行い、変化していれば、Trueを「ObjectDecomposerOnChanged」に渡します
image.png

なおRotationは「FloatQUpdateChecker」で処理していますが、コチラはFloat3では無く、FloatQで比較を行います

①-2:オブジェクト属性のJSON化

オブジェクトから取り出したPosition/ScaleなどのXYZ座標値や、RotationのXYZWの4値は、「XYZJsonBuilder」によって、JSON化します
image.png

「ToJSON」でキー名と各値をJSONキーバリュー形式にします
image.png

ちなみにPosition/Scaleは3値なので、「XYZJsonBuilder」で処理しますが、Rotationは4値なので、「XYZWJsonBuilder」で処理していますが、要領はXYZJsonBuilderと同じです

①-3:JSON化されたオブジェクトPosition/Rotation/Scaleを連結

JSON化されたオブジェクトPosition/Rotation/Scaleは、カンマ区切りで連結する必要があるため、「JSONBuilder」で繋ぎ合わせます(幾つか空欄のテキスト入力を接続していますが、これはデバッグ用なので、気にしないでください)
image.png

①-4:オブジェクト属性JSONにオブジェクト名を付与

JSON化されたオブジェクトPosition/Rotation/Scaleの上位に、オブジェクト名(オブジェクトのSlotから取得)の付与を「ObjectJSONBinder」で行います
image.png

なお、VR |> AR投影アプリでは、オブジェクトのユニーク性を、オブジェクト名で行っている(もっと良いオブジェクトを一意に識別できる情報がNeosVRオブジェクトに存在していたら、ぜひ教えてください)ため、投影したいオブジェクトは、全て名前を変えておく必要があります

②:オブジェクト属性群を接続してWebSocket送信

複数のオブジェクト群の属性を1つのJSONに繋ぎ合わせ、WebSocket送信する「ObjectJsonSender」は、「ProjectorJsonBuilder」と「TimingReducer」、「WebSocketSend」で出来ています
image.png

②-1:複数のオブジェクト群の属性を1つのJSONに繋ぎ合わる

「ProjectorJsonBuilder」は、個々のオブジェクト属性を、1つのJSONに繋ぎ合わせ、その上位にくる「id」や「data」キー、それらに関するデリミタを付与し、デバッグしやすくするための改行も付与します
image.png

②-2:オブジェクト属性群JSONをWebSocket送信

ここまでで、送信するJSONは出来上がったので、最後に、WebSocketでこのJSONを送信する部分です

まずNeosVRでWebSocketを扱うには、何らかのオブジェクトに、「Attach Component」で「WebSocketClient」を追加してあげる必要があります

ここでは、下図右にあるコーン(三角錐)のオブジェクトに、「WebSocketClient」をアタッチしました
image.png

②-2-1:WebSocket接続、チャンネルjoin

その後、WebSocketClient配下の「IsConnected」にチェックを入れると、このオブジェクトからWebSocketでElixirに接続します
image.png

接続後は、「neos:logix」というWebSocketルーム(後述するElixir側でこのルームを構築します)に「phx_join」を投げるというjoin用パーツ「WebSocketSendJoin」を作ります

ここでWebSocket送信のために、「WebSocket Text Message Sender」というノードを使います
image.png

このパーツが出来上がったら、「Pulse」をクリックすれば、ルームにjoinできます

②-2-2:WebSocket送信

それから、送信するJSONをWebSocket送信するパーツ「WebSocketSend」を作りますが、ここでも「WebSocket Text Message Sender」を使います

なお、WebSocket送信間隔を「TimingReducer」内にある「Timer」で0.1秒間隔で定期送信するようなロジックになっており、FPSを意図的に抑制していますが、上記で「ObjectDecomposerOnChanged」によりオブジェクトのPosition/Rotation/Scaleが変わったときのみTrueを返す部分も作っているため、「オブジェクト変化があったら送信」で繋ぎ変えるとFPSを落とさずに連携するモードになります

もしくは、「0.1秒間隔経過、かつオブジェクト変化があったら送信」というような形にすると、ムダな通信量を削減できます
image.png

ここまででNeosVR側は完了で、オブジェクトの変化がElixir側に送信されるようになります

Elixir側

Elixir側は、非常にカンタンで、「Channel」という機能を使ってWebSocketサーバを立てて、NeosVRから受け取ったオブジェクト属性群をブロードキャストしているだけです

Phoenix PJ配下に生成済みの下記コードに、コメントアウトを解除するだけで、WebSocketサーバの構築は完了です

/lib/basic_web/channels/user_socket.ex
defmodule BasicWeb.UserSocket do
  use Phoenix.Socket

  ## Channels
  # channel "room:*", BasicWeb.RoomChannel
  channel "neos:*", BasicWeb.NeosLogixChannel  # <- radd here

WebSocket受信時の処理は、下記のようなコードを作成し、handle_in()でWebSocket受信時のアクションを書いてあげればOKです

/lib/basic_web/channels/neos_logix_channel.ex
defmodule BasicWeb.NeosLogixChannel do
	use Phoenix.Channel

	def join( "neos:logix", _message, socket ) do
		{ :ok, socket }
	end

	def handle_in( "new_msg", %{ "body" => body }, socket ) do
		broadcast!( socket, "new_msg", %{ body: body } )
		{ :noreply, socket }
	end
end

参考:VR |> AR投影アプリ

VR |> AR投影アプリは、この中では最もヘビィな造りをしていて、今回の本題から逸れるため、別の機会にシェアしたいと思いますが、概要だけお伝えすると、ARアプリ側で、現実を写すカメラ画像の上に、NeosVRから送られたオブジェクト属性群JSONを元に、ARオブジェクト生成/変更/消滅を行い、重ね合わせを行っているだけです

そのため、Elixirでのデータ加工等は特に行っておらず、NeosVRから受け取ったJSONをそのままElixirがブロードキャストし、それをVR |> AR投影アプリが受け取り、上記AR処理を行っています

VR |> AR投影アプリでどんなことが可能になるのか?

NeosVR内で作ったオブジェクトやワールドや、NeosVRに取り込んだCADデータを、任意の緯度/軽度に出現させ、それをARグラスやARコンタクトで見ることで、「現実空間へのデジタル建造」が誰にでも出来るようにします

これを応用して、航空機やドローンで撮影した街や家屋の点群データをNeosVRに取り込み、その土地に住む方も、これから移住を考えている方も、果ては遠く海外からも、NeosVR内で改造した街に実際に行き、街歩きしながらAR投影で自分の作った街を楽しめる … そんな未来の地方創生を、NeosVR+Elixirで叶えていく活動をしています

現時点では、VRとARを繋ぐテクノロジーがまだあまり発展していないため、それをイチ早く実現/体験できるNeosVR+Elixirには、とてつもなく大きな可能性があると見ています

いま作っているもの

オブジェクト群のPosition/Rotation/Scaleのリアルタイム反映と、テクスチャ/メッシュのプリロード、親子関係を持つオブジェクトの一斉同期までは出来ていて、下記が現在、開発中です

  • オブジェクトテクスチャのNeosVRからVR |> AR投影アプリへのリアルタイム反映
  • WebSocket経由の通信でバイナリも投げられるようにする
  • 現時点は、NeosVRとVR |> AR投影アプリの両方にテクスチャを別々にインポートしている
  • オブジェクトメッシュのNeosVRからVR |> AR投影アプリへのリアルタイム反映
  • NeosVR側が「MeshX」という形式を使っているので、まず解析から
  • 現時点は、NeosVRとVR |> AR投影アプリの両方にメッシュを別々にインポートしている

MeshXの攻略を一緒にやってくれる方、絶賛募集中です

最後に

VR進化の最先端である「NeosVR」と、プログラミング言語進化の最先端である「Elixir」の2つが悪魔合体させると、わりかし気軽に、「VR空間」と「現実世界」を繋げられることが伝われば幸いです

私自身、NeosVRでVRプログラミングに触れ始めて、まだ日も浅いため、NeosVR側の解説は拙いところも多いのですが、こうした活動にご興味あれば、下記の私のTwitter DMでご連絡ください

piacere の Twitter DM(リンク先の赤枠部分をクリックしてください)
https://twitter.com/piacere_ex
image.png

p.s.このコラムが、面白かったり、役に立ったら…

image.pngimage.png にて、どうぞ応援よろしくお願いします:bow:


明日の記事は、@rhenium_vrcさんの「NeosFesta2を支えるダイナミックスポーンシステム」です

29
12
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
29
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?