
1+4=作品解説~HeartBeat Decoding2(Emotion Words)編②~
合同展示会『1+4=』を開催しました
自分が代表と務めるメディアアート集団"WONDEMENT"は昨年12月3〜9日の7日間、横浜・桜木町の横浜市民ギャラリーで第4回展示かつ初の合同展となる『1+4=』を開催しました。

WONDEMENTメンバーが学生時代に立ち上げた桜美林大学のメディアアートサークル「Mapper」との合同展である本展示ではメイン作品1点とサブの作品2点の合計3点を展示し、自分が全体のプロデュースと2つの作品制作に携わっています。
今回はその『1+4=』で展示し、自分が制作を担当したサブ作品『HeartBeat Decoding2(Emotion Words)』の作品解説Part2になります。
↓Part1はこちらから!
前回は作品の概要と中核となっている心拍数と重量の計測・取得の過程について解説しました。
今回は取得した心拍と重量の値をビジュアライズする仕組みの制作過程について解説していきます。
感情とリンクしたテキストを考える
本作品は『HeartBeat Decoding2(Emotion Words)』という名前にもある様に心拍数に連動する感情として出力し流れ出ている様子を表します。
今回は心拍数60回/分をベースとして3段階の感情に分けています。
60~80:Relax(リラックス)
81~100:Nomal(ノーマル)
100~120:Excitement(興奮)
そしてこのリラックス、ノーマル、興奮の3つの状態から連想される単語をChatGPTで複数候補出しを行い、そこから各状態につき7つの英単語をピックアップしました。

ピックアップしたテキストは最終的にText TOPでouchDesignerに入れ込みます。

最終的にはこの単語を心拍数に応じて切り替えていきますが、その仕組みは後ほど解説します。
テキストが流れるように動く

作品はこのようなText TOPで入れた単語が上から滝のように流れてくるような動きをしながら動作します。
移動のアニメーションを作る
テキストの移動自体はTranceform TOPで付けていきますが、流れるように動く必要があるので動きの仕組みは下記画像の様にして作っています。

左側の「Start」、「End」はそれぞれConstantで動きの開始位置と終点位置を指定しています。
これをInterpolateでキーフレーム化し、かつ間を補完する入力を作成します。
上のConstantでは速度を指定しています。
Constantの値をSpeedに入れ、lookupでInterpolateの値と合わせることでConstantに入力した速度で「Start」、「End」の位置に移動する値を作成しています。
これをTranceform TOPにインポートすることでテキストが動くようになっています。
また、これだけでは一度開始点から終点に移動しただけで止まってしまうため、Speed CHOPにある「reset」を定期的に押す仕組みを作る必要があります。
アニメーションが繰り返し再生される様にする

そのための仕組みが上記画像左側にある「relax_Timing」です。
それ自体はNullですが、大元は下記画像にあるLFOとLogicを組み合わせて一定間隔でパルス信号が発信される様になっています。

LFOのタイミングを調整することでテキストが移動し終えたタイミングでパスが発信され、再び上から降ってくる動きが開始される様になっています。
アニメーションの開始タイミングをずらす
基本的にはこの仕組みをコピーして単語毎に適用していくのですが、動き出すタイミングが同じだと違和感があり、単語ごとに微妙に動き出すタイミングが異なるようにしました。

そこで上記画像にあるDelay CHOPをLFOから伸びるLogicと「relax_Timing」の間に噛ませています。
このDelay CHOPを7つ用意しそれぞれの遅延タイミングを微妙にずらすことで揃って流れてくることを防止しています。
テキスト位置をランダムにする
これでテキストが流れる仕組みが完成しましたが、いざ動かすと物量が足りない感じがあったので、1つの単語からTranceformを2つ伸ばして1つの感情あたり7種類、14個の単語が流れる様にしました。

また、現状だと各単語が同じX座標上とy軸上に上下に移動していますが、これだとランダム感が少なくもっと滝の様に降っている様子を演出するために毎回X座標があらかじめ設定した座標候補内からランダムに選択されて変更される様にしています。
それを実現しているのが下記画像のconstant郡と「RandomCHOP COMP」です。


「RandomCHOP COMP」は有志の方が作成したtoxになります。
(下記URLからDL可能です)
パラメータ内の「Range」に出力されて欲しい値の幅を入力し「Generate」を押すと「Seed」に入力されたシード値を元に「Range」にある数値内からランダムに値が出力されるという代物です。
今回は下記画像の様に8つの値を用意し、それをSwitchで切り替えることでX座標を変更出来るようにしています。
そのためRangeには0,7を入力している他、シード値はTranceform TOP毎に異なっていないと被ってしまうのでTranceform TOPの数だけRandomCHOP COMPを用意してそれぞれに適当な値を入力しています。

値を出力するタイミングについては移動を開始する際に決定出来ていれば良いため、テキストを動かすタイミングを司っている「relax_Timing」のパルスをインポートしています。
心拍数と連動してパラメータをコントロールする(速さ、背景色)
次に心拍計からOSCで送信している心拍数を組み込みます。
心拍数に応じた単語の切り替え
背景色の変更
背景の雨粒アニメーションの発生頻度
心拍計の値は上記3つの要素に連動しています。
心拍数に応じた単語の切り替え
まずは単語の切り替えです。
Text TOPはTranceformで動きや位置のアニメーションを付けた後、感情の種対別にまとめてComposite TOPで合成しています。
そのため感情毎の各Composite TOPをSwitch TOPで切り替えればOKですが、そのSwitch TOPのIndexにインポートする値を用意する必要があり、実際に下記の様に作成しました。

左上のOSC in CHOPで心拍の値を取り込んだ後、心拍数以外の値も入っているためSelect CHOPで心拍数のみ取り出します。
それをExpression CHOPに入れて下記のエクスプレッションを書きます。
(0 if 60 <= me.inputVal <= 80.99 else 1 if 81 <= me.inputVal <= 100.99 else 2 if 101 <= me.inputVal <= 120 else -1)
この場合、心拍数が60~80.99までの場合は「0」、81~100.99までの場合は「1」、101~120までの場合は「2」が出力される様になっています。
大抵の場合60を下回ったり、120を超えるケースはなく本番でも問題なく動作していました。
あとはこの値はSwitch TOPのIndexにエクスポートすれば心拍数に応じて各感情毎の単語群が滝の様に流れてくる様になります。
背景色の変更
背景色の変更はベースとなった『HeartBeat Decoding』でも使った仕組みを流用しています。

上記画像右下のmath CHOPに心拍数を入れ、60~120の範囲で0~1になるようにレンジを変更します。
前述の通り60を下回ったり120を超えることは基本ないためこの設定で問題ありませんでした。
後は60の時と120の時用の色をSwitch TOPに入れ、パラメータの「Blend between Inputs」をONにすることでカラーがブレンドして行きながら心拍数が上がるほどに色が遷移していく様になります。
背景の雨粒アニメーションの発生頻度
雨粒アニメーションの頻度調整もカラーとほぼ同様です。

頻度に関係するパラメータにインポートする値があるため、そこに心拍数の値を入れてmath CHOPでレンジを調整したものをインポートするだけです。
これにより心拍数が落ち着いているときはポツポツと弱く雨が降っているように見え、心拍数が上がるとザーザー降りになっていきます。
重量と連動してパラメータをコントロールする
重量についてはPart1でも少し触れた様に第二回展示「With」で制作した『IKEBANA(ReBuild)』のシステムを流用しています。
そのためArduinoのセッティングなどは『IKEBANA(ReBuild)』の解説noteをご覧いただければと思います。
ただ、『IKEBANA(ReBuild)』では取得した重量データから重量差を計算していましたが、本作品では重量データを単語のフォントサイズと連動させています。
仕組み自体は下記の形になっています。

色々なノードがありますが、そのほとんどは前回の流用で今回の肝となる部分は下側の下記部分です。

実際に重量計に手を乗せて想定される重量を把握し、それを元に背景色の変更などでも使ったmath CHOPを使ってのレンジ変更で任意のフォントサイズ範囲に収まるよう調整しています。

今回の場合は概ねMaxが800だったため、何も乗っていない=0から想定されるMax重量=800までをちょうど良いフォントの範囲(今回であれば30~45)になるよう設定しています。
あとはこれをText TOPのパラメータにある「Size」二インポートするだけです。
出力する
これで各種機構が完成しました。
最後にテキストと背景を合成してWindow COMPに入れてモニターへ出力します。
整理する
出来るだけ共通化し調整を反映しやすくミスを減らす

今回のノード構成はこの様になっています。
第三回展示で制作・発表した『Tech Synthesizer』もかなりカオスな構成でしたが、それ以上にカオスになっていると思います。
とはいえテキストの入れているText TOPやTranceform、アニメーションに関連するConstantやSpeed、lookupなどを一つの塊としてそれが単語毎に用意されているだけなので、単語の数だけ増えているだけで中身自体はそこまで複雑ではありません。

合計21つあるだけ
単語のアニメーション開始タイミングをバラつかせるためのDelayや、X座標をランダムにするための値は同じものを使うなどして共通化を図っている部分もあります。
こうすることで単語や感情の種類にかかわらず全体に関係するパラメータが共通化され、1つのノードのパラメータを変更することでその結果が全体に反映される様になり制作的にもPC負荷的にも負担が減るようにもしています。
また、TOP系を始めとする2D処理のみで作られていることも大きいですが、上記の様な負荷軽減も行ったことで性能の高くないミニPCで動作させることが出来ています。
↓ミニPCについては下記でレビューを書いています。
Annotate機能を活用する
また、今回は初めて本格的に「Annotate」機能を使い、このノードやノード群が何を司っているのか視覚的に探しやすく分かりやすい様にもしています。

Annotate使うことで下記画像の様にノードを囲うことができ、システムの機能ごとに囲うことでその機能を構成しているノード郡はどこにあるのかを試薬的に分かりやすくすることが出来ます。

最後に
ここまで2回に分けて『1+4=』で展示した『HeartBeat Decoding2(Emotion Words)』の作品解説をしてきました。
基本的にはTouchDesignerのみで完結している作品ですが、心拍と重量という2つのセンサーを使いこれまでに制作した作品のブラッシュアップも兼ねている作品となっています。
過去トップクラスに複雑なシステムなので解説がとてつもなく長くなってしまいましたが、次回の作品解説はメイン作品である『Move Decoding(Voxel)』の解説です。
それではまた!