前置き
現在所属しているライブサークルで、今まで照明をdmxで光らせていたのをUnity上の仮装灯台を光らせるようにしなくちゃいけなくなった。そこでArtnetを使ったプラグインをつくったので投稿します。(今回のソースコードはこちら)
※注意: DaLight4でArtnetを使うには専用のデバイスの購入が必要です
内容
ArtNetはUDP通信を用いてdmxのデータを送信できる照明界隈で使われているプロトコル。これ使えば実際の照明もUnityとかUE4なんかで作ったバーチャル照明を同様に光らせることができます。
今回やりたかったことを図で説明するとこんな感じ。現在サークルで使っているDasLightというソフト側からイーサネット経由でUnityに信号を送った。
実装について
ArtNetのプロトコルについてはwikiとドキュメントを読みました
こいつによると受け取ったバイト列は次の表のようになるとのこと
index | 中身 |
---|---|
0 ~ 7 | Protocol (Art-Net) |
8, 9 | Opcode ArtDMX (0x5000) little endian |
10 | Protocol Version Hi (0) |
11 | Protocol Version Lo (14) |
12 | Sequence (255周期) |
13 | Physical |
14,15 | Universe little endian |
16 | Length Hi |
17 | Length Lo (2 to 512, even) |
18 ~ | Data |
あとはこの表に従ってUdp通信で受け取ったデータをArtnetDataクラスを作成し、コトラクタで初期化を行いました。
/*!
* Copyright (c) 2021 Takuya Isaki
*
* Released under the MIT license.
* see https://opensource.org/licenses/MIT
*/
using System;
using UnityEditorInternal;
using UnityEngine;
namespace ArtNet.Runtime
{
public readonly struct ArtNetData
{
#region public filed
public readonly ArtNetOpCode OpCode;
public readonly int Sequence, Physical, Universe;
public readonly int[] Channels;
public readonly int ProtocolVersionHi, ProtocolVersionLo, LengthHi, LengthLo;
#endregion
#region public method
/// <summary>
/// コンストラクタ
/// Art-Net Structure
/// 0 ~ 7 : id 「Art-Net」
/// 8 ~ 9 : Opcode ArtDMX (0x5000) little endian
/// 10 : Protocol Version Hi (0)
/// 11 : Protocol Version Lo (14)
/// 12 : Sequence (255周期)
/// 13 : Physical
/// 14 ~ 15 : Universe little endian
/// 16 : Length Hi
/// 17 : Length Lo (2 to 512, even)
/// 18 ~ 530 : Data
/// </summary>
/// <param name="buf">受信したbyte列</param>
public ArtNetData(byte[] buf)
{
var buffer = new byte[530];
Buffer.BlockCopy(buf, 0, buffer, 0, buf.Length);
OpCode = (ArtNetOpCode)BitConverter.ToInt16(new byte[2] { buffer[8], buffer[9] }, 0);
ProtocolVersionHi = buffer[10];
ProtocolVersionLo = buffer[11];
Sequence = buffer[12];
Physical = buffer[13];
Universe = BitConverter.ToInt16(new byte[2] { buffer[14], buffer[15] }, 0);
LengthHi = buffer[16];
LengthLo = buffer[17];
Channels = new int[512];
for (int i = 18; i < buffer.Length; i++)
Channels[i - 18] = buffer[i];
}
public static bool IsArtNet(byte[] buffer)
=> buffer[0] == 'A' &&
buffer[1] == 'r' &&
buffer[2] == 't' &&
buffer[3] == '-' &&
buffer[4] == 'N' &&
buffer[5] == 'e' &&
buffer[6] == 't' &&
buffer[7] == 0x00;
public void Logger()
{
string str = "";
str += $"Opcode : {this.OpCode}\n";
str += $"ProtocolVersionHi : {ProtocolVersionHi}\n";
str += $"ProtocolVersionLo : {ProtocolVersionLo}\n";
str += $"Sequence : {Sequence}\n";
str += $"Physical : {Physical}\n";
str += $"Universe : {Universe}\n";
str += $"LengthHi : {LengthHi}\n";
str += $"LengthLo : {LengthLo}\n";
foreach (var t in Channels) str += t + "\n";
Debug.Log(str);
}
#endregion
}
}
受信時はOpCodeをOpDmxのものを扱いたいので、下のようにコードを書く。
using ArtNet.Runtime;
using UnityEngine;
public class SampleLightReceiver : MonoBehaviour
{
[SerializeField] private ArtNetClient client;
[SerializeField] private new Light light;
private void Start()
{
this.client.onDataReceived += data =>
{
if (data.OpCode == ArtNetOpCode.OpDmx)
{
light.color = new Color(
data.Channels[0],
data.Channels[1],
data.Channels[2]);
}
};
}
}
参考文献