読者です 読者をやめる 読者になる 読者になる

The jonki

呼ばれて飛び出てじょじょじょじょーんき

[Unity] [OSC] UnityでOSCを使う(UnityOSC)

Unity Unity

UnityでOSCを使う方法がないか探してみたところここが、githubでコードを公開しているものがあった。

UnityOSC


これを使ってUnityでOSCでメッセージを送受信してみます。Unityとの通信相手に今回はTouchOSCというiPhoneのアプリを使います。動作確認用なのでOSCアプリは何でも良いです。

環境構築

  • UnityOSCをダウンロードUnityOSCのページの右下の方にあるDownload ZipをクリックしてUnityOSCをダウンロードします。pullしても良いけど。
  • Unity空プロジェクトを作成し、展開したUnityOSCのフォルダをAssets下に適宜配置します。OSCController.csは今回使うサンプルスクリプト(後で解説)です。展開方法はどうでもいいけどOSCHelper.csはUnityのエディタ拡張のコードなのでEditorフォルダを作成し、必ずその下に置いてください。[Window] -> [OSC Helper]という感じで表示されるはず。
Assets/
          Editor/
                    OSCHelper.cs
          OSC/
                    OSCBundle.cs
                    OSCClient.cs
                    OSCHandler.cs
                    OSCMessage.cs
                    OSCPacket.cs
                    OSCServer.cs
          Scripts/
                    OSCController.cs // 今回自分で追加したファイル          
  • 空のGameObjectを作成して追加したOSCController.csを貼付けます。

コード修正

そのままでも良いですが、送信先のIPアドレスや送受信ポートの指定がコード内で行っていたのでこれをUnityのインスペクタビューから編集できるようにします。


OSCController.cs
OSCController.csというファイルをちゃっかり先ほど追加しましたが、これはフォルダに入っていたoscControl.csをベースにしたものです。StartのところでOSCHandlerのシングルトンを取得してInitしているのでそこで、ネットワーク情報を送るようにします。これらのネットワーク情報はクラスの冒頭でpublic変数にして定義しているので、インスペクタから直接編集できるようになります。

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

public class OSCController : MonoBehaviour {
    #region Network Settings
    public string TargetAddr;
    public int OutGoingPort;
    public int InComingPort;
    #endregion
    private Dictionary<string, ServerLog> servers;

    // Script initialization
    void Start() {  
        OSCHandler.Instance.Init(TargetAddr, OutGoingPort, InComingPort);
        servers = new Dictionary<string, ServerLog>();
    }

    // NOTE: The received messages at each server are updated here
    // Hence, this update depends on your application architecture
    // How many frames per second or Update() calls per frame?
    void Update() {
        // must be called before you try to read value from osc server
        OSCHandler.Instance.UpdateLogs();

        // データ受信部
        servers = OSCHandler.Instance.Servers;
        foreach( KeyValuePair<string, ServerLog> item in servers )
        {
            // If we have received at least one packet,
            // show the last received from the log in the Debug console
            if(item.Value.log.Count > 0) 
            {
                int lastPacketIndex = item.Value.packets.Count - 1;

                UnityEngine.Debug.Log(String.Format("SERVER: {0} ADDRESS: {1} VALUE 0: {2}", 
                item.Key, // Server name
                item.Value.packets[lastPacketIndex].Address, // OSC address
                item.Value.packets[lastPacketIndex].Data[0].ToString())); //First data value
            }
        } 

        // データ送信部
        if(Input.GetMouseButtonDown(0)) {
            Debug.Log("SendMessage");
            var sampleVals = new List<int>(){1, 2, 3};
            OSCHandler.Instance.SendMessageToClient("iPhoneTouchOSCApp", "/hoge/a", sampleVals);
        }
    }
}


OSCHandler.cs
今まではここでネットワーク情報がべた書きでしたが、これはOSCController.csから指定するように変更します。といってもInit関数の引数を追加するだけです。あと少しわかりにくいですがCreateClientでUnityから送信する側、CreateServerでUnityで受信する側の設定になります。直感的に逆な気もしますが、よしとします。

public void Init(string targetAddr, int outGoingPort, int inComingPort)
{
    //Initialize OSC clients (transmitters)
    // Sender
    CreateClient("iPhoneTouchOSCApp", IPAddress.Parse(targetAddr), outGoingPort);

    //Initialize OSC servers (listeners)
    // Receiver
    CreateServer("SomeOscClient", inComingPort);        
}

実行

[Window] -> [OSC Helper]でOSCHelperウインドウを見て実行!そうするとOSC Helperのエディタ上に設定した相手との通信状態が表示されます。コンソールにはTouchOSCから飛んで来た値が随時表示されるようになります。また、マウスをクリックするとOSCデータを相手のOSCクライアントに送信します。TouchOSCではデータを受信するとデータ送信部に光るアイコンの下が光るのでデータが飛んで来ていることがわかります。


おわり