20
17

More than 5 years have passed since last update.

TouchDesignerの正しい表記について啓蒙する音連動映像コンテンツの制作

Last updated at Posted at 2017-12-04

はじめに

こんにちは、oishihiroaki(irishoak)です。

昨今、TouchDesignerのユーザーの拡がり目覚ましいですが、その陰でTouchDesignerと正しく表記がなされなかったために、若者がTouchDesigner警察に注意を受ける事案がありました。

TouchDesigner警察

案外知られていないことですが、公式では、“Touch Designer”と単語の間にスペースを挟まず、“TouchDesigner”と表記するのが適切なようです。(大文字小文字についてはこだわりはないんだろうか…)

世間にはそもそもTouchやDesignerの正しい綴りを覚えられない幼稚園児もいますが、
幼稚園児

まずは正しい表記を覚えて、健全なTouchDesigner開発を行うことができるようになりたいものです。今回はそのために、TouchDesignerの正しい表記を印象的に脳に刻み込むことができるようなコンテンツを作成いたしました。この記事では、その作成過程について解説したいと思います。

コンテンツ概要

音声ファイルを再生して、音の強さを取得し、その強さによって、TouchDesignerのテキストが動きます。TouchDesignerの文字の間のスペースがなくなれば、背景のポリスメンの絵が、OKジェスチャに変化します。

動画 TouchDesignerPoliceAudioReactive

画像1

画像2

画像3

制作プロセス

このサンプルコンテンツのプロジェクトデータはこちらのGithubリポジトリにアップしています。
TDPoliceAudioReactive Github

プロジェクトフォルダの作成

TouchDesignerを起動し、File > Create Project Folder からプロジェクトフォルダを作成します。

プロジェクトフォルダ作成1

Project Folder に TDPoliceAudioReactive(任意) と入力し、
Rename File、Media Folders の AudioImages の チェックボックスをチェックし、Createボタンを押します。

プロジェクトフォルダ作成2

そうすると、.toeファイルと、AudioImageというフォルダが同階層に作られます。

プロジェクトフォルダ作成3

音声ファイルの再生と解析

デフォルトで存在しているオペレータオブジェクトを消去し、
OP Create Dialog から
CHOP > Audio File In、CHOP > Audio Device Out オペレータを作成し、以下のように接続します。

オーディオの読み込みと再生

サンプルの音声ファイルが再生されるようになりました。

CHOP > Analyze オペレータを作成し、ノードを接続。
LRの2つのチャンネルのオーディオデータが得られます。

オーディオの解析

CHOP > Math オペレータを作成し、ノードを接続。
Combine ChannelsAverage
Channel Post OPPositive に変更します。
これにより、LRの2つのチャンネルが一つにまとめられ、正負の値をとっていたものが、絶対値をとり正の値に修正されます。

オーディオの解析2

CHOP > Filter オペレータを作成
これにより、値の変化が滑らかになります。
このままだと、現在の値を計算するためにサンプルする幅が広く、音の特徴が消えた値になってしまいます。そこで、Filter Width0.15 ぐらいに調整します。サンプリングする幅が変化し、音の特徴をある程度保った値が得られます。

オーディオの解析3

CHOP > Null オペレータを作成し、接続しておきましょう。

オーディオの解析4

TouchDesignerテキストオブジェクトの作成

COMP > Geometry オペレータを作成し、ダブルクリックして中に入り、すでに存在するTorus SOPを削除します。

Geometryオペレータを作成

SOP > Fontオペレータを2つ作成します。
2つあるFontオペレータのTextプロパティにTouch
もう一つに、Designerと入力します。(※つづりに注意してください!)

Level of Detail の 値を調整することにより、フォントのメッシュの分割具合が調節できます。

フォントの作成

SOP > Extrude オペレータを2つ作成し、それぞれ接続します。
これにより、テキストが押し出されました。
Depth Scaleによって押し出しの奥行きのスケールが調整できます。 0.25 ぐらいにしましょう。
この状態であると、厚みを変化させた時に、原点とオブジェクトの中心がずれてしまいます。そこで、
Depth Translate のExpressionに me.par.depthscale*-0.5 と入力します。

Expressionを記述する際、まず、Depth Scaleの入力ボックス上で、右クリックをし、ポップアップからCopy Parameter をクリックします。それから、Depth TranslateのExpression入力ボックス上で、右クリックをし、Paste Referencesをクリックします。そうすると、Depth Scaleの参照である me.par.depthscale がペーストされます。この辺りは、Houdiniと共通ですね。

フォントの押し出し

SOP > Merge を作成し、ノードを接続します。
これにより、2つのSOPが一つのSOPにまとめられました。

SOP > Null を作成し、ノードを接続し、右下の紫と青の●にチェックを入れ、RenderフラグとDisplayフラグをONにします。

フォント結合

uキーを押して上の階層に戻ります。

背景の作成

絵文字(Apple製)画像データの取得

絵文字の画像データを手に入れます。
Emojipedia Apple Emoji List
ここより、Apple製の Police OfficerGesturing OK の絵文字の画像を(手動で…)保存します。
画像データはプロジェクトフォルダのImageディレクトリの下に、PoliceOfficerGesturingOKというフォルダを作り、それぞれ分けて保存します。

画像の保存

2D Texture Array に絵文字画像データを読み込む

TOP > Texture 3D オペレータを作成します。
このオペレータではボリュームデータや、2D Texture Array として複数のテクスチャを1つのデータにまとめて扱うことができます。

2つ作成したら、プロパティを、
Type2D Texture Array
Pre FillON
Replace SingleON
Cache Size12
に変更します。

Texture 3D

TOP > Movie File In オペレータを2つ作成します。
Viewerフラグ (左上の○)を OFF にし、
FileのExpression に './Image/PoliceOfficer' と入力、
もう一つの Movie File In オペレータでは、
'./Image/GesturingOK' と入力、
Play ModeSpecify Index
Index のExpressionに me.time.frame-1 と入力、
単位をIndex に変更します。

画像の読み込み

Texture 3Dオペレータに接続すると、画像がまとめて読み込まれると思います。
(うまく読み込まれない場合、Texture 3DResetプロパティを一度ONにしてからOFFにしてみてください)

Texture 3D TOP

画像の読み込み2

GLSLによる背景エフェクトの作成

TOP > GLSL オペレータを作成します。

Uniform変数の設定

Vector 1 タブ を開き、
Uniform Nametime
それぞれ、
value0x : me.time.frame
value0y : me.time.seconds
value0z : absTime.frame
value0w : absTime.seconds
と入力します。
これで、シェーダ内で時間のデータがとることができるようになります。

Python Tips #Time
absTime Class

GLSLの作成

修正点(Uniform floats should specified on 'Vectors' pages)
以下、Arrays1audioVolume を定義していますが、Windows のIntel GPUでは、uniform float audioVolume がうまく機能しないようで、Vector1ページに記述するべきです。
Github issues #4 (Uniform floats should specified on 'Vectors' pages)
33601153-b98bbc7e-d9ee-11e7-8f31-f85073104ccf.png

Arrays1 タブを開き、
一番上の CHOP のテキストボックスに、null1オペレータをドラッグ&ドロップします。
Uniform NameaudioVolume と入力します
これで、シェーダ内で音の強さのデータを取得できるようになります。

GLSLの作成2

解像度の設定

解像度を設定します。
Common タブを開き、
Output ResolutionCustom Resolution
Resolution1280 720 と設定します。

GLSLの作成

GLSLにTexture 3Dを接続

作成したGLSLオペレータの第1入力に、PoliceOfficerを読み込んだTexture 3Dオペレータ、第2入力に、GesturingOKを読み込んだTexture 3Dオペレータを接続します。

コードの記述

glslと紐付いたglsl1_pixelのEditボタンを押し、GLSLのコードを記述します。

GLSLの記述

修正点(macOS GLSL compiler stricter than Windows)
2D Texture Array
こちらには、冒頭で
#extension GL_EXT_texture_array : enable
を記述してね、とあったのですが、これを記述するとMacOSでコンパイルエラーを起こします。コメントアウトしましょう。
Github issues #3(macOS GLSL compiler stricter than Windows)

TDPoliceAudioReactiveEmojiTileBackgroundEffect.glsl
/**
 * TDPoliceAudioReactive EmojiTile Background Effect
 */

// 2D Texture Array を 有効に (I's not necessary)
// #extension GL_EXT_texture_array : enable

// 2D Texture Array の画像数
#define TEX_ARRAY_NUM 12

// 時間(frame, seconds, absTime.frame, absTime.seconds)
uniform vec4 time;
// 音の強さ
uniform float audioVolume;
// 出力するフラグメントのカラー
out vec4 fragColor;

void main()
{
    // アスペクト比 (1280, 720) 
    vec2 aspectRatio = vec2(1.7777777, 1.0);
    // 縦のタイル(タイル一つに絵文字が一つ表示される)の数 --- 時間によって変動させる
    float tileNumV = 12.5 + 10 * sin(time.w * 0.5);

    // UV座標値 --- 中央 半タイル分ずれた位置でスケーリングされるようにオフセットをかける
    vec2 halfTileSize = vec2(1.0/(tileNumV * aspectRatio.x) * 0.5, 1.0/tileNumV * 0.5);
    vec2 uv = vUV.xy - vec2(0.5, 0.5) + halfTileSize;
    // 縦横のそれぞれのタイル数
    vec2 tileNum   = vec2(tileNumV * aspectRatio.x, tileNumV);
    // タイルのUV(画像を表示するときに使用)
    vec2 tileUv    = mod(uv.xy, 1.0/tileNum) * tileNum;
    // タイルのインデックス(タイルごとに異なる画像を表示するために使用)
    vec2 tileIndex = floor(uv.xy * tileNum.xy) / tileNum.xy;

    // タイルインデックスごとに異なるシンプレックスノイズパターン(0.0~1.0)を取得
    // (ポリス絵文字をノイズ模様で出しわけするために使用)
    float snoisePattern = 0.5 + 0.5 * TDSimplexNoise(vec3(tileIndex.xy * aspectRatio, time.w * 0.5));
    // タイルインデックスごとに異なる中央から広がるパターン(0.0~1.0)を取得
    vec2 diffCenterToEachTile = tileIndex * aspectRatio;
    float circleWavePattern = mod(2.0 * dot(diffCenterToEachTile, diffCenterToEachTile) + time.w * -0.75, 1.0);

    // ポリスの画像カラーを取得
    vec4 policeTexCol    = texture(sTD2DArrayInputs[0], vec3(tileUv.xy, snoisePattern     * TEX_ARRAY_NUM));
    // OKジェスチャの画像カラーを取得
    vec4 okGestureTexCol = texture(sTD2DArrayInputs[1], vec3(tileUv.xy, circleWavePattern * TEX_ARRAY_NUM));

    // ポリス絵文字タイルの背景の色 --- サイレンのように赤と青に交互に切り替わるように
    vec3 policeTexColBgCol = 0.6 * mix(vec3(1.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0), 0.5 + 0.5 * sin(time.w * 20.0));
    // 背景の色とブレンド
    policeTexCol.rgb = mix(policeTexColBgCol, policeTexCol.rgb, policeTexCol.a);

    // OKジェスチャ絵文字タイルの背景の色
    vec3 okGestureBgCol = vec3(0.0);
    // 背景の色とブレンド
    okGestureTexCol.rgb = mix(okGestureBgCol, okGestureTexCol.rgb, okGestureTexCol.a);

    // 音の大きさによって、警察とOKジェスチャの画像を入れ替える
    vec3 color = mix(policeTexCol.rgb, okGestureTexCol.rgb, smoothstep(0.5, 0.8, audioVolume));

    // 出力するフラグメントのカラーをセット
    fragColor = TDOutputSwizzle(vec4(color, 1.0));
}
タイルのUVとインデックスを算出

絵文字をタイル状に敷き詰めるために、タイルのUVとインデックスをそれぞれ、mod関数とfloor関数を使って求めます。
modは剰余、floorは小数点以下の値を切り捨てた値を返します。
UVとインデックスを画像として表示するとこのようになります。

▼ タイルのUV
タイルのUV

▼ タイルのインデックス
タイルのインデックス

※ 除算は演算コストが高く、シェーダプログラミングではできるだけ使用は避けるべきです。1.0/tileNum など行っていますが、すべてのピクセルで共通の値は、事前にCPU上で計算し、uniform変数としてGLSLに渡した方が本来は良いです。

ノイズパターンを取得

ポリスの絵文字がノイズ模様になるように描画するポリスの画像の種類が変わるようにします。そのために、タイルのインデックスによって異なるノイズの値を算出します。
TouchDesignerには、TDSimplexNoise(vec3 v)というシンプレックスノイズを返す関数が用意されています。うれしいですね。引数には、xy成分に、タイルのインデックスz成分に時間を渡し、時間で変化する2Dのノイズパターンを得ます。

2Dのノイズパターン

2D Texture Array から 画像のカラーデータを取得

2D Texture Arrayのデータを取得するためには、sTD2DArrayInputs 変数を使用します。この変数は配列構造になっており、[0]にはGLSL Topの第1入力に接続したTexture 3Dオペレータのデータ、[1]には第2入力に接続したデータが渡されます。
実際に、カラーデータを取得するには、texture(sTD2DArrayInputs[0], vUV.stp)関数を使用します。第1引数には2D Texture Array を第2引数にはuvデータを渡します。uvデータの各成分は、.stが画像のUV座標.p成分は、2D Texture Arrayの配列番号に対応します。p成分の配列番号は整数で指定するようになっており、0や0.5を指定した場合は、0番目の画像が、2.0や2.9と指定した場合は2番目の画像が取得されます。

音の強さによってポリスとOKジェスチャの画像の切り替えを行う

音による画像の切り替えは以下のコードで実現しています。
vec3 color = mix(policeTexCol.rgb, okGestureTexCol.rgb, smoothstep(0.1, 0.9, audioVolume));
mix関数は第1引数と第2引数に指定した値を、第3引数に指定した値(0.0~1.0)によってブレンドします。
smoothstepは、第3引数に指定した値が、第1引数と第2引数で指定した値の範囲で変化するときに、滑らかに0.0~1.0の範囲で変化するような値を返します。
つまり、音の強さの値が0.1から0.9で変化するときに0.0から1.0の値が返され、画像が(比較的)滑らかに切り替わるようになります。

GLSL Topを記述する際は、ここの情報を参照されてください。
TouchDesigner Write a GLSL TOP

TouchDesignerテキストを音の強さで動かす

音の強さによって先ほど作成したテキストが動くようにします。
テキストの Geometory TOPをダブルクリックして中に入ります。

修正点 : SOP cooking order optimization
以下、サンプルでは、Font SOPで、移動のためのExpressionを記述していますが、これだと、処理コストが高い Font SOP と Extrude SOP が毎フレーム実行されてしまい、パフォーマンスが落ちてしまいます。。
そのため、それぞれの文字の処理の後に、Transform SOP を配置し、そこで移動のためのExpressionを記述することで、Font SOP、 Extrude SOP での不要な実行を防ぐことができ、高速化を図ることができます。
Github issues #2(SOP cooking order optimization)
add Transform SOP

「Touch」の方のFontオペレータの
Center Text VerticallyOff に、
Translateプロパティのtyに -0.25 と入力、
txのExpressionに min(-1.525, -1.525-1.0+op('../null1')['chan1']) と入力します。
Extrude SOP のあとに、Transform SOP を作成し、その Translate tx プロパティのExpressionに min(-1.525, -1.525-1.0+op('../null1')['chan1']) と入力します。これによって、音が大きければ真ん中にスライドするようになりました。

TouchDesignerテキスト

「Designer」の方のFontオペレータも、
Center Text VerticallyOff
Translateプロパティtyに -0.25
txのExpressionは max(2.175, 2.175+1.0-op('../null1')['chan1']) と入力します。
Extrude SOP のあとに、Transform SOP を作成し、その Translate tx プロパティのExpressionに max(2.175, 2.175+1.0-op('../null1')['chan1']) と入力します。

TouchDesignerテキスト2

テキストを回転させる

uキーを押し、上の階層に移動します。

geo1 オペレータの Rotate の Expression にそれぞれ以下のように入力します。
rx : absTime.seconds * 30.0
ry : absTime.seconds * 40.0
rz : absTime.seconds * 10.0

これで、時間によって、テキストがぐるぐると回転するようになりました。

TouchDesignerテキスト3

テキストのレンダリングと外側光彩エフェクト

TOP > Render オペレータを作成します。
また、COMP > Camera、COMP > Light も作成します。テキストが描画されるようになりました。

テキストを描画

外側光彩のためのブラーエフェクトの作成

TOP > Blur を作成し、
Pre-Shrink3
Filter Size10
に設定します。

Blurオペレータ

TOP > Monochrome を作成し、
RGBAlpha
AlphaAlpha
に設定します。

Monochromeオペレータ

TOP > Constant を作成し、カラーの設定をします。

TOP > Multiply を作成し、
Fixed LayerInput1 に設定。
第1入力に、mono1を、
第2入力に、constant1を接続します。
そうすると、Constantで設定した色の、テキストのシルエットがぼけた画像が得られます。

Multiplyオペレータ

BlurMultiply の間に、Level TOP を挟んで、Gamma の値を高く設定すると、光彩の強さを上げることができます。このように、簡単にポストエフェクトを使うことができるのはTouchDesignerの強みですね。

TOP > Over を作成し、
第1入力に、render1
第2入力に、multiply1 を接続します。
これで、テキストの後ろの外側光彩エフェクトがかかった画像が得られました。

外側光彩エフェクトの合成

合成

TOP > Over を作成し、
第1入力に、over1
第2入力に、glsl1 を接続します。

TOP > Out を作成し、over2 を接続します。
これで完成です。

合成

まとめ

いかがでしたでしょうか。これでもう、TouchとDesignerの間にスペースを入れることはなくなることと思います。

私自身、TouchDesignerに関しては初心者であり、誤りや非効率的な実装を行っている箇所があるかと思います。そのような点を見つけられましたら、ご指摘いただけると幸いです。TouchDesignerは、他のツールと比較して動画再生周りとても強く、何度か案件で命を救われました。それに対しての感謝を込めて少しでもコミュニティに寄与できればと思います。

最後に、このような下らないものを作ってしまい本当に申し訳ありませんでした。

20
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
17