[Unity][OculusRift]VRアトラクションにおける振動ユニットの利用とステレオ化について

はじめに

VR コンテンツにおいて、触覚等のフィードバックがあると没入感が上がってより楽しくなったりします。

拙作の VR アトラクションでもこれまで扇風機や噴霧器の制御を行ってきましたが、今回新たに振動ユニットも追加してみました。

上記コンテンツでプレイヤーが乗る飛行機は左右に二基のエンジンがあり、振動ユニットを椅子の座面左右に設置してそれぞれ制御することでイメージと近い体感が再現できるのではないか、と考えたことが動機です。

振動ユニットについて

振動ユニットの先行事例については izm 氏のロボット操縦コンテンツ「めかしむ☆」をはじめ多数あり、 利用にあたっても同氏の記事( VR環境における簡単な振動ユニットの使い方について - izm_11's blog )を参考にさせて頂いております。

振動ユニットは上記記事で紹介されているのと同じで以下のものです。ひとつ 4,000 円くらいと安価で買えます。

【お一人様2点まで】 スピーカーでは再現しきれない重低音の臨場感を振動で再現 50Wハイパワー振動ユニット ボディソニック トランスデューサ ホームシアター 上海問屋 DN-82305 | 【上海問屋】通販サイト

低音域でよく振動するスピーカーで、機器との接続も音声デバイス扱いになります。

20 Hz ~ 100 Hz 程度の可聴域ギリギリの周波数帯でよく振動するのと、そうでない音を入力すると普通に鳴ってしまうので、通常はサブウーファー用出力などローパスフィルタをかけたソースを入力します。

これを椅子の裏面などに、振動がよく伝わるようネジ止めして使います。

VR での利用とステレオ化

さて、こちらの振動ユニットの通常の用途は、既存の映画やゲーム等に接続するだけで低音があるシーンで振動するというものです。

VR コンテンツでも、普通に使う分にはコンテンツ内で低音を鳴らしておけば、あとはスピーカー/ヘッドフォン出力を分岐した先でサブウーファー出力(1 ch)を取り出し、そこに振動ユニットを接続すれば使えます。

これをステレオ化、すなわち椅子の座面の左右に取り付けてそれぞれ別の振動をさせるとなると、課題がいくつか発生します。

基本的な方針としては、左右の振動ユニットをそのまま音声出力の LR に割り当てて、低音の定位(パン)を適用することを考えます。

しかし、通常のヘッドフォン用音声出力は VR HMD に合わせて定位が回転してしまうので、分岐して使うことはできません。

そのため、振動ユニットをヘッドフォン用とは別の音声デバイスとして接続し、プログラム側で鳴らす低音のソースや定位を自前で制御する必要があります。

または、コンテンツの音をヘッドフォンでなくスピーカーから出す場合は VR HMD の回転の影響を受けずに済みますが、単純に分岐してから 2.1ch アンプ等に繋いでサブウーファー出力を取ると 1ch になってしまうので、LR それぞれに個別にローパスをかける必要があります。

(余談ですが、音をスピーカーから出す話は こちら)

今回のコンテンツではヘッドフォンを利用するため、前者の方法になります。低音の定位をすべて自前で計算しないといけないのが手間ですが、今回は飛行機のエンジンの振動に絞って実装して簡略化することにしました。

(手間といっても、各振動源との距離を出して、それに基づいてボリュームとパンを計算するくらいだと思います。遮蔽物の影響など考えだすと厳しくなりますが…)

こちらの構成では別デバイスから低音のみを出力するためローパスは不要ですので、適当なステレオアンプがあればよいです。

しかし、デバイスによってはパンの特性がいまいちで、例えば私のノート PC のステレオミニ出力から、右のチャンネルにのみ音声信号の入った 2ch のデータを再生しても、左からも少し音が鳴ってしまいます。

これでは振動の定位を感じにくいので、USB → ステレオミニ変換できる適当な USB オーディオアダプタ経由などで接続し、同データでちゃんと左が無音(無振動)になることを確認します。

必要な機能

  • スピードに連動して振動の強さを変えたい → ボリューム調整
  • カーブ時は外周側のエンジンを強く、内周側を弱く振動させたい → パン
  • エンジン稼働から徐々に、ゴ、ゴ、ゴ、ゴゴゴ…と周波数を上げていきたい → 周波数コントロール
  • (複数の振動ソースの合成 → ミキシング ※ 今回はエンジンのみのため不要)
いずれも通常の音声処理の枠組みでできそうです。

実装

別デバイスから音を再生する必要がありますが、Unity ではデフォルトの音声デバイス以外使えません。対処方法はいくつか考えられますが、今回は Windows のネイティブプラグインを書きます。

API はお好みでよいですが、ボリューム、パン、周波数のコントロールと複数ソースのミックスのサポートがあるものを選んでおくと手抜きができます。

今回は XAudio2 を使いました。パンはないので左右チャンネルのボリュームで自前実装します。

古いという点を除けば多分 DirectSound がパンもあって楽だと思います。ローレベルの API で波形を自前でいじってもよいです。マルチプラットフォーム対応したいなら OpenAL もよいかもしれません。

さて、ベースとなる波形データはプログラム内部で作成することも可能なのですが、今回はファイルを読み込んでループ再生しておき、そのボリューム、パン、周波数を随時コントロールする方式にしました。

方形波、ノコギリ波などいくつか試しましたが、単純なサイン波がわりとエンジンっぽかったので、20 Hz のサイン波をベース波形として使うことにしました。

ちなみに、波形データの wav ファイルの作成には、単純な波形を合成して効果音を作れる、開発室 Pixel 様のピストンノイズが非常に便利です。

あとは Unity 側で、飛行機の状態に合わせてネイティブプラグイン側に指示を出したり、エンジン音(聞こえる方)を振動と同じように制御してやれば完了です。

なお、ネイティブプラグイン以外の選択肢としては、プロセス間通信(ローカル/ネットワーク)や Arduino を使うなども考えられます。

椅子について

振動ユニットからの振動を座面に十分に伝えるために、木などの固い素材にネジ止めしてやる必要があります。

しかし、移動に車を利用しない身としては椅子を持ち運ぶ運用はきびしいですし、折り畳み椅子でも結構かさばります。

というわけで作ったのがこちら。


これなら現地でお借りした椅子の上に置けばよく、座敷での飲み会でも利用可能。リュックサックに詰めて山も登れます。

アンプの電源もゴツいモバイルバッテリー( 700-BTL017BK )があればギリギリ何とかなりますし、まだコンセントがなくても持ち込みデモが可能…!

演出や体感について

とりあえず飛行機の発進時に「オッ」と言ってもらえたり、体験後に「振動があると違う(良い)」くらいの感想はいただけることが多いです。

一方で、ステレオであることに直接言及されることはほぼありません。

ステレオと知らずに体験しても自然で特に言うことはない、と受け取れなくもないですが、ステレオの振動でも、リアルというよりは違和感を減らす程度の意味合いが強いので、モノラル→ステレオ対応のコスパは振動なし→モノラルに比べると良くない感はあります。

このへんの話は、扇風機も正面から 2 段階でなんとかなる( VR向け風量制御の先行事例とイルカラスでの実現方法模索 - Togetterまとめ )という話と近い領域な感じです。

振動は、例えば左から右に振動を移動させている間はそれがよくわかる一方、ずっと右だけ振動させていてもあまり右だと感じにくいといった性質があると思います。(私個人の感覚に基づきますが、人間の感覚全般にそうした性質があるような認識をもっています)

そのため、カーブ時の振動の計算式にメリハリをつけたり、飛行機にトラブルが生じるシーンでのエンジン停止→再開など、なるべく変化をつけるような演出を意識しています。

(VR 空間内での移動に応じた振動のフィードバックがあることによる酔いの低減効果、もしかしたら多少は期待できるかも…と思ったりもしますが、十分な比較データがないと何とも言えないですね。東京オッキューランド出展時のアンケート集計を見る分には、激しく動くコンテンツの割には酔われにくい模様です)

おわりに

既存コンテンツへの追加コストが低い、というこのデバイスの大きな魅力の一つを殺している感がありますが、ステレオ化自体は悪くないんじゃないかと思います。コスパは低下します。

あと、音声デバイス別系統に分けるくらいなら、Arduino + 振動モーターみたいな選択肢もありそうですね…。

コメント