この記事は 福島高専 Advent Calendar 2021 25日目(最終日)の記事です。
1. はじめに
こんにちは、高専4年のAkkunlabです。主にプログラミングや電子工作などをしています。
去年のAdvent Calendarでは「ちょっとすごいと思わせるデジタルアートを作ってみた」というタイトルで、インタラクティブなLEDアートについて記事を書きました。
今回はその進化版として50台のPCを使用したデジタルアートを制作したので、記事にしていきたいと思います。
読みにくいところがあるかもしれませんが、最後まで読んでいただけたら幸いです。
目次
1. はじめに
2. 制作したアート
3. システム構成
4. Server側プログラム
5. Client側プログラム
6. 完成した作品
7. 開発環境
8. おわりに
9. 参考
2. 制作したアート
今回制作したものは、複数台のPCやスマホを制御することで一つの大きなディスプレイとして表現できるアートです。
この作品は、Web上で動作するアプリケーションであり、簡単にディスプレイを追加・制御することができます。
有線接続でマルチディスプレイをする感覚と同じように、複製したり、拡張することができます。(今のところは、一部の映像のみ共有できます)
従来のマルチディスプレイと異なるのは、無線で接続しているということです。この通信にはSocket.IOを使用しています。
無線接続のため、少し遅延が生じる場合があります。そのときは、制御画面よりデバイス別に制御することで全体のズレを小さくすることが可能です。
3. システム構成
今回のアートを作るにあたって、システムの構成は下の図のようにします。
① 制御PCからServerに表示命令を送信。
② Serverから各デバイスへ表示命令を送信。
表示命令を送信する前に、あらかじめ全てのデバイス時刻を同期させます。表示命令には「表示を実行する時刻」が含まれており、その時刻になると各デバイスで表示するようにしています。
また、以下のように同じページで表示(入室)と制御(管理)を簡単に切り替えられるようにしています。
4. Server側プログラム
今回使用したServer側プログラムの一部です。Server側にはNode.jsを使用しており、ServerとClient間の通信にはSocket.IOを使用しています。
はじめに、入室処理です。
// 入室
socket.on('join', data => {
eventName = data.name;
const user = new User(socket.id, data.displayName); // インスタンスを作成
if (!eventsList[eventName]) eventsList[eventName] = {}; // Objectがない場合はObjectを作成
if (eventsList[eventName].managerId) {
events.to(eventsList[eventName].managerId).emit('mDataAdd', user); // managerにデータを送信
}
eventsList[eventName][user.myId] = user; // userを追加
});
// 管理者入室
socket.on('mJoin', data => {
eventName = data.name;
const user = new User(socket.id, data.displayName); // インスタンスを作成
if (!eventsList[eventName]) eventsList[eventName] = {}; // Objectがない場合はObjectを作成
events.to(socket.id).emit('mData', eventsList[eventName]); // managerにデータを送信
eventsList[eventName][user.myId] = user; // userを追加
eventsList[eventName].managerId = user.myId; // managerを追加
});
表示側の入室イベントを受信すると、Userインスタンスを作成します。Userクラスにはid、名前、作成日のプロパティがあります。
また、入室する部屋を管理するeventsList
にuser
を追加します。
管理側の入室では、表示側と同様にUserインスタンスを作成します。そして、eventsList
に管理者として追加します。
次に、制御側の表示命令及び管理についての処理です。
// 管理システム変更
socket.on('MSChange', data => {
if (data.id === 'ms_change_unit_data') {
eventsList[eventName][data.value.id].myName = data.value.number; // 名前を更新
events.to(data.value.id).emit('MSChange', data); // 送信
} else {
data.time = Date.now() + 5e3;
socket.broadcast.emit('MSChange', data); // 送信
}
});
管理システムの変更イベントを受信すると、その種類によってデータを表示側に送信します。
最後に、退出処理です。
// 退出
socket.on('disconnect', () => {
if (!eventsList[eventName]) return; // 入室0人の場合
if (!(socket.id in eventsList[eventName])) return; // 未入室の場合
// managerの場合は削除
if (eventsList[eventName].managerId) {
events.to(eventsList[eventName].managerId).emit('mDataDelete', eventsList[eventName][socket.id]); // managerにデータを送信
if (eventsList[eventName].managerId === socket.id) {
delete eventsList[eventName].managerId;
}
}
delete eventsList[eventName][socket.id]; // userを削除
});
退出イベントを受信すると、eventsList
からuserを削除し、管理者に送信します。
5. Client側プログラム
今回使用したClient側プログラムの一部です。Client側は表示側、管理側どちらも一つのプログラムで動作しています。
また、ちょっとした演出はThree.jsを使用しています。Three.jsを使用したプログラムは以前にいくつか作成していますのでこちらをご覧ください。
主なイベント処理です。
// 管理者Data
socket.on('mData', data => {
mData = data;
objects.createUnits(mData); // データを表示
});
// 管理システム変更
socket.on('MSChange', data => {
// 動画を表示・非表示
});
mData
イベントを受信すると、データを更新し管理画面を再構築します。
MSChange
イベントを受信すると、その内容に従って動画を表示・非表示させます。
より詳しく知りたい方は、コードをGithubにあげていますのでこちらをご覧ください。
6. 完成した作品
完成した管理(制御)システムです。
各デバイスが登録した名前が一覧で表示されています。クリックすることで個別に制御することが可能です。
上の水色のボタンは共有する動画を読み込むものです。
完成したアートの動画です。
先日、ディジタルアートイベントを開催しました!
— あつし (@atsushi_nit) December 25, 2021
PC約50台を同時に使用したアートです。過去最高の作品になったと思います🎄
参加していただいた皆様、本当にありがとうございました!! pic.twitter.com/GUrzj6Yxlq
7. 開発環境
- Windows10
- Socket.IO 4.0.0
- Three.js r131
8. おわりに
今回は、複数ディスプレイを使用したアートを制作しました。
準備を手伝っていただいた皆様、本当にありがとうございました!
過去最高のデジタルアート作品を完成させることができました!!
最後まで読んでいただき、ありがとうございました!