小嶋秀樹 | 研究室
日本語 | English
Unity + OSC

Unity に OSC による通信機能を与えることで,他のコンピュータとの通信が可能になります.ここでは,その基本として,Unity における OSC 通信機能のセットアップ方法と使い方について解説します.たとえば,つぎのような使い方が考えられます.

【OSC とは】

OSC(Open Sound Control)とは,送信者(クライアント)から受信者(サーバ)へ,つぎのようなデータを送るための仕組みです.ひとつの通信データは,アドレスパターン(たとえば /kozPhone/uniVRtutorial2/message)とそれに続く引数の列(たとえば 320 150 "Game Over")からなります.アドレスパターンによって,ディレクトリ階層のように,データの意味づけを表示します.引数としては,整数(int32)・実数(float)・文字列などが使えます.

もともとは電子楽器のコンピュータ制御のためにつくられましたが,今ではさまざまな用途に使われています.通信の実装部分には UDP を利用することが多いようです.UDP とは,IP(Internet Protocol)を使ったデータ通信方法のひとつです. ここでも UDP を使った OSC について解説します.

【OSC を Unity に組み込む(Unity がクライアントの場合)】

まずは jorgegarcia/UnityOSC をダウンロードし,その src フォルダを,Unity プロジェクトの Assets フォルダに入れてください.Unity から Assets/src/OSCHandler.cs を開き,たとえば Unity 側を受信者(サーバ)とする場合は,つぎのように "//" を消して,該当コードを有効化します.また,適当なサービス名(たとえば "uniVRtutorial2")と使用するポート番号(たとえば 8001)を指定してください.

OSCHandler.cs
public void Init()
{
    //Initialize OSC clients (transmitters)
    //Example:        
    //CreateClient("SuperCollider", IPAddress.Parse("127.0.0.1"), 5555);

    //Initialize OSC servers (listeners)
    //Example:
    CreateServer("uniVRtutorial2", 8001);
}

なお,ここでは「サーバ」「クライアント」という表現をしますが,イメージとしては,VR 世界を提供する Unity が「サーバ」となり,その世界に働きかけるためのセンサ(Leap Motion プログラムなど)が「クライアント」となります.

つぎに,Unity 世界の適当なオブジェクト(ここでは Ground)に新しいスクリプトを追加します.Hierarchy から Ground を選び,つぎのように編集します.UnityOSC で必要となるタイムスタンプ処理が含まれていますが,実際に利用する場合は,アドレスパターンごとに引数を処理することになります.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityOSC;

public class GroundBehavior : MonoBehaviour {

    private long lastTimeStamp;

    // Use this for initialization
    void Start () {
        //  OSC の初期化(受信開始)
        OSCHandler.Instance.Init();
        lastTimeStamp = -1;
    }
    
    // Update is called once per frame
    void Update () {
        //  受信データの更新
        OSCHandler.Instance.UpdateLogs();
        //  受信データの解析
        foreach (KeyValuePair<string, ServerLog> item in OSCHandler.Instance.Servers) {
            for (int i=0; i < item.Value.packets.Count; i++) {
                if (lastTimeStamp < item.Value.packets[i].TimeStamp) {
                    lastTimeStamp = item.Value.packets[i].TimeStamp;
                    //  アドレスパターン(文字列)
                    string address = item.Value.packets[i].Address;
                    //  引数(とりあえず最初の引数のみ)
                    var arg0 = item.Value.packets[i].Data[0];
                    //  処理(とりあえずコンソール出力)
                    Debug.Log(address + ":" + arg0);
                }
            }
        }
    }
}

Unity 世界を動かし,しかるべき OSC 送信者(クライアント)を接続すると,ウィンドウ下のコンソール部分に受信データが表示されているのがわかります.クライアント側では,IP アドレスとして Unity が動作している PC を指定し,ポート番号として 8001 を指定してください.

なお,ここでは「地面」にスクリプトを加えましたが,たとえば OSC データで「ボール」のようなオブジェクトを動かす場合は,「ボール」自体のスクリプトに上記の赤字部分を書き加えるとよいでしょう.

【OSC を Unity に組み込む(Unity がサーバの場合)】

Unitiy 側から他のアプリ(サーバ)に OSC データを送信する場合も,基本的には同じようなスクリプトになります.まず,OSCHandler.cs では,CreateClient() を有効にし,適当なサービス名(たとえば "uniVRtutorial2new")を与え,接続先となるサーバの IP アドレス(同一 PC であれば 127.0.0.1)とポート番号を指定します.

OSCHandler.cs
public void Init()
{
    //Initialize OSC clients (transmitters)
    //Example:        
    CreateClient("uniVRtutorial2new", IPAddress.Parse("127.0.0.1"), 8001);

    //Initialize OSC servers (listeners)
    //Example:
    //CreateServer("AndroidPhone", 8001);
}

つぎに,Unity 世界の送信者となるオブジェクトに新しいスクリプトを追加します.ここでは,オブジェクトの位置(transform.position)を OSC サーバに送信するスクリプトとしています.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityOSC;

public class GroundBehavior : MonoBehaviour {

    private long lastTimeStamp;

    // Use this for initialization
    void Start () {
        //  OSC の初期化(受信開始)
        OSCHandler.Instance.Init();
    }
    
    // Update is called once per frame
    void Update () {
        //  単一データの送信
        OSCHandler.Instance.SendMessageToClient("uniVRtutorial2new", 
                                                "/positionX", 
                                                transform.position.x );
        //  複合データの場合は
        //  List<object> values = new List<object>();
        //  values.AddRange(new object[]{transform.position.x, 
        //                               transform.position.y, 
        //                               transform.position.z });
        //  OSCHandler.Instance.SendMessageToClient("uniVRtutorial2new", 
        //                                          "/positionXYZ", values );
    }
}

OSC データを受信するサーバを Pd で用意するなら,たとえば次のようなパッチになるでしょう.参考にしてください.