今日の内容
オーディオビジュアルその2 : プロジェクトの構造化
複数の画面(シーン)を切り替える
COMPによる構造化
パフォーマンスモード
調査 : 最終発表をどんな内容にするか?
プロジェクトの構造化
複数のシーン(画面)を切り替えるには?
前回作成したオーディオビジュアルのプロジェクト
一つだけで長時間持たせるのは難しい
複数のシーン(モード?)を切り替えていくと飽きられない
しかし、全ての機能を一様にネットワーク化していくと巨大なものに…
どのように整理していくか?
Base COMPを利用して構造化していくと便利!
複数のオブジェクトを1つにまとめる
前回の音の高・中・低域それぞれに反応する球を題材に
ダウンロード
オペレーターをまとめる手順
まとめたいオペレーターを全て選択
画面を右クリックしてメニュー表示
「Collapse Sellected」を選択
選択した部分が1つのBase COMPに
1つのCOMPにまとまった状態に!
名前をつけてあげると、さらに分かりやすい
まとめたBase COMPをtoxファイルに保存して再活用
toxに保存
1つにまとめたBase COMPをミギクリック
メニューから「Save content .tox …」を選択
.tox 形式でファイル保存
保存したtoxを別のプロジェクトで使用
新規にプロジェクト作成
toxファイルをドラッグ&ドロップ
TOXのサンプル
以下から5種類ダウンロード
tox1 , tox2 , tox3 , tox4 , tox5
In と Out
ダブルクリックして保存したBase COMPの内部を表示
入出力
TOP、SOP、CHOPそれぞれに存在
複数のInやOutを配置することも可能
複数のBase COMPを組合せ
詳細はパッチを作成しながら解説!
ダウンロード
複数のBase COMPの切り替え
手動版 (keyType In CHOP + switch TOP)
ダウンロード
複数のBase COMPの切り替え
自動版 (Auidoa Analysis COMPを使用して自動スイッチング)
ダウンロード
デザイナーモードとパフォームモード
TouchDesignerの2つのモード
パフォームモードではフルスクリーンで作品を表示するだけでなく様々な設定が可能
実際に操作しながら解説
例: フルスクリーンで表示しながら操作するGUIを別ウィンドウで表示
参考: Widget Tutorials
VIDEO
アンケート
アンケート
TouchDesignerのプロジェクトは階層構造を持っています。作成しているプロジェクトの中に複数のオペレーターをまとめた「サブパッチ」のような構造を作ることが可能です。複数のオペレータをまとめるにはContainer COMPを使用します。Container COMPは、複数の入力と出力を設定したり、他のオペレータの値を参照することが可能です。さらに、このContainerの仕組みを応用してGUI (グラフィクスユーザーインターフェイス) が作成できます。Widgetというユーザーインターフェイスに特化したCOMPを使用してボタンやスライダーといった様々なパーツを組合せて独自のGUIを構築して画面上に配置したり、別ウィンドウで表示することが可能です。
スライド資料
サンプルファイル
参考: Widget Tutorials
VIDEO
今回も前回に引き続いてTouchDesignerとGLSLを組合せて高度な表現に挑戦します。前回はフラグメントシェーダー (ピクセルシェーダー) を用いてテクスチャー (TOP) を生成する2次元的な表現に留まっていました。今回はさらにGLSLを応用して3次元の形態(SOP)にGLSLを適用していきます。まず始めにGLSL TOPを用いてバンプマッピング (Bump mapping) をPhongマテリアル(Phong MAT)に適用しレンダリングの際に3Dの形状を変形するという手法を行います。さらに、続いて、GLSL MATを使用して頂点シェーダー (vertex shader) を用いて座標の情報をもとにマテリアルを動的に生成する手法に挑戦します。
スライド資料
サンプルプログラム
今日の内容
TouchDesignerでShader (GLSL) を使ってみる – 応用編
フラグメントシェーダ (ピクセルシェーダー) を使ってSOPを変形
バンプマッピング、法線マッピング、ハイトマップ を使う
GLSL MAT
Vertex Shaderについて
GLSL MATの使い方
フラグメントシェーダ(ピクセルシェーダー)でSOPを変形
GLSL TOPのフラグメントシェーダー(ピクセルシェーダ)でSOPを変形
バンプマッピングという手法を使用する
陰影計算に用いる物体表面の法線ベクトルをテクスチャによって「揺らす」ことによって物体表面に凹凸が付いたような陰影を得る手法
法線マッピング (Normal Mapping)
バンプマッピング的技法の一種
より詳細なオブジェクトの法線ベクトルのX, Y, Z座標に対応したRGB画像
今回やってみること
フラグメントシェーダーの出力のTOPを3つのマッピング用データに分解
カラーマップ – SOPに貼り付けるRGPのイメージ
法線マップ – 法線ベクトル用に返還したデータ
ハイトマップ – 全体の大きな凹凸を表現するデータ
Fragment Shaerは前回作成した波紋状に拡がるフラングメントシェーダーを使用
uniform float time;
uniform vec2 resolution;
out vec4 fragColor;
void main() {
vec2 uv = (gl_FragCoord.xy * 2.0 - resolution) / vec2(resolution.x, resolution.x);
float len = length(uv);
float r = sin(len * 24 - time * 2.0 - 0.8) * 0.5 + 0.5;
float g = sin(len * 24 - time * 2.0 - 0.4) * 0.5 + 0.5;
float b = sin(len * 24 - time * 2.0) * 0.5 + 0.5;
vec4 color = vec4(r, g, b, 1.0);
fragColor = TDOutputSwizzle(color);
}
GLSL TOPの出力を、カラーマップ、法線マップ、ハイトマップに分解、Phong MATのパラメータにする。
Phong MATのRGBのパラメータにそれぞれのマップを適用
バンプマッピングを適用したPhong MATで、Grid SOPをレンダリング
フラグメントシェーダーが立体の凹凸に変換される!
入力するSOPをGirdからSphereへ、カメラのアングルを調整
GLSLで複雑に変形する球体に!
入力するフラグメントシェーダーを変えたり、ノイズを追加したりなど工夫してみる
完成!
GLSL MATを使ってみる
ここまで使用してきたのはGLSL TOP → フラグメントシェーダーのみ
TouchDesignerには、GLAL MATというのもある
フラグメントシェーダーに加えて、頂点シェーダー (Vertex Shader) も記述可能
頂点の情報を利用、編集できる
復習: 頂点の3D座標情報から画面の全ピクセルに描画されるまでの流れ
GLSL MATを配置してみる
以下のように頂点シェーダーとフラグメントシェーダーが同時に追加される
初期状態の頂点シェーダー(glsl_vertex) ※解説入り
// 3Dオブジェクトの各頂点の最終的な描画位置を計算するシェーダー
void main() // 各頂点に対して並列で実行されるメイン関数
{
// --- 1. 頂点のワールド座標を計算 ---
// Pは入力された頂点の初期位置(モデル座標)
// TDDeform()は、SOPなどで設定されたジオメトリの変形を適用し、
// ワールド空間における頂点位置を算出するTouchDesignerの組み込み関数
vec4 worldSpacePos = TDDeform(P);
// --- 2. ワールド座標から最終的な描画位置(クリップ座標)へ変換 ---
// TDWorldToProj()は、ワールド座標に対し、カメラの位置や向き(ビュー変換)と
// 遠近法(プロジェクション変換)を適用する組み込み関数
// gl_Positionは、頂点の最終的な座標を格納する必須の出力変数
gl_Position = TDWorldToProj(worldSpacePos);
}
このVertex Shaderは、以下の2段階の処理を実行しています。
入力された頂点座標 P に対し、TouchDesignerで設定された変形を適用し、ワールド空間での位置 worldSpacePos を求めます。
その worldSpacePos を、カメラの情報を用いてスクリーン上の描画座標 gl_Position へと変換します。
これは、3Dグラフィックスにおける頂点処理の基本的な流れを、TouchDesignerの便利な組み込み関数を使って実装した典型的な例です。
GLSL 頂点シェーダーで使用される座標系
モデル座標 (Model Coordinates)
オブジェクト単体を基準とした、その物体固有の座標系です。「ローカル座標 (Local Coordinates)」とも呼ばれます。
目的 : 3Dモデルを制作する際の基準となります。
原点 : 通常、そのオブジェクトの中心や基点(ピボット)が原点 (0, 0, 0)
となります。
特徴 : この座標系はオブジェクトごとに独立しており、他のオブジェクトとの位置関係は考慮されません。例えば、自動車のモデルであれば、その車体の中心が原点となり、タイヤやドアの位置はそこからの相対的な座標で定義されます。
ワールド座標 (World Coordinates)
シーン内のすべてのオブジェクトを配置するための、共通のグローバルな座標系です。
目的 : 複数のオブジェクトやカメラ、ライトなどを一つの仮想空間上に配置し、それらの絶対的な位置関係を定義します。
原点 : シーン全体の基準となる不動の原点を持ちます。
変換 : オブジェクトをワールド座標に配置するには、モデル座標に対して移動(Translate)・回転(Rotate)・拡大縮小(Scale)といった「モデル変換」を行います。これにより、各オブジェクトがシーン内のどこに、どの向きで、どれくらいの大きさで存在しているかが決まります。
クリップ座標 (Clip Coordinates)
カメラから見える描画範囲を定義するための座標系 です。Vertex Shaderにおける最終的な出力座標 (gl_Position
)がこれにあたります。
目的 : 画面に描画する領域と、描画しない領域(クリッピング領域)を決定します。
変換 : ワールド座標に対し、以下の2つの変換を行って得られます。
ビュー変換 (View Transform) : ワールド座標系を、カメラの位置と向きを基準とした座標系(ビュー座標系)に変換します。
プロジェクション変換 (Projection Transform) : カメラの視野(画角、アスペクト比、見える距離の範囲など)を考慮し、遠近法を適用して、最終的な描画範囲(クリッピング空間)に座標を投影します。
特徴 : このクリッピング空間は通常、立方体や直方体で定義されます。この範囲内に収まるジオメトリだけが描画対象となり、範囲外のものは描画処理から除外(クリッピング)されます。
これらの座標系の関係性を、オブジェクトが画面に表示されるまでの流れで示すと以下のようになります。
モデル座標 でオブジェクト(部品)を作る。
「モデル変換」を行い、ワールド座標 (仮想空間)にオブジェクトを配置する。
「ビュー変換」と「プロジェクション変換」を行い、カメラから見たクリップ座標 に変換する。
クリップ座標に基づいて描画範囲が決定され、最終的にスクリーン座標(画面上のピクセル位置)へと変換されて表示されます。
頂点シェーダーとフラグメントシェーダーの連携
頂点シェーダーで取得した頂点の情報を、フラグメントシェーダーに送ってみる
頂点シェーダ側: out、 フラグメントシェーダー側: in を使う
頂点シェーダーをから座標情報を出力 (コメント入り) (glsl_vertex)
// Vertex ShaderからFragment Shaderへ渡すデータ群を定義
// 'oVert'という名前の箱に詰めて渡すイメージ
out Vertex {
vec4 color; // 頂点カラー
vec3 worldSpacePos; // ワールド座標
vec3 worldSpaceNorm; // ワールド座標系での法線ベクトル
flat int cameraIndex; // 描画しているカメラのインデックス
} oVert;
// メイン関数
void main() {
// --- 1. 頂点位置の計算(前回と同様の処理) ---
vec4 worldSpacePos = TDDeform(P);
gl_Position = TDWorldToProj(worldSpacePos);
// --- 2. Fragment Shaderへ渡す各種データを準備 ---
// カメラのインデックスを取得
int cameraIndex = TDCameraIndex();
oVert.cameraIndex = cameraIndex;
// ワールド座標を格納
oVert.worldSpacePos.xyz = worldSpacePos.xyz;
// インスタンシングを考慮した頂点カラーを取得
oVert.color = TDInstanceColor(Cd);
// 変形を適用した法線ベクトルを計算し、正規化して格納
vec3 worldSpaceNorm = normalize(TDDeformNorm(N));
oVert.worldSpaceNorm.xyz = worldSpaceNorm;
}
このシェーダーは、前回解説した基本的な頂点位置の計算に加え、後続のフラグメントシェーダー(Fragment Shader)で、より高度なライティング(陰影処理)や色付けを行うための様々な情報を準備し、引き渡す役割を担っています。
このVertex Shaderは、単に頂点を画面上のどこに描画するかを決めるだけでなく、後工程であるFragment Shaderがリアルな質感(陰影や色)を表現するために必要となる、以下の4つの重要な情報を計算し、提供する役割を果たしています。
カメラ情報 : どのカメラから見ているか
ワールド座標 : 3D空間内の正確な位置
頂点カラー : インスタンスごとの色を含むカラー情報
法線ベクトル : 光の当たり方を計算するための面の向き情報
次にこの情報を受けとって3D空間のワールド座標系の情報で模様を生成するフラグメントシェーダーを作成してみましょう。
フラグメントシェーダー (glsl_pixel)
// Vertex Shaderから渡されたデータを受け取るためのブロック
// 'iVert'という名前の箱からデータを取り出すイメージ
in Vertex {
vec4 color;
vec3 worldSpacePos;
vec3 worldSpaceNorm;
flat int cameraIndex;
} iVert;
// シェーダーの最終的な出力色を定義
out vec4 fragColor;
// メイン関数。ピクセルごとに並列で実行
void main() {
// 1. ピクセルを描画せずに破棄するかチェック
TDCheckDiscard();
// 2. ワールド座標に基づいて色を計算
// sin関数を使い、位置に応じて周期的に変化する値を生成
float r = sin(iVert.worldSpacePos.x * 20.0); // X座標から赤(R)成分を生成
float g = sin(iVert.worldSpacePos.y * 20.0); // Y座標から緑(G)成分を生成
float b = sin(iVert.worldSpacePos.z * 20.0); // Z座標から青(B)成分を生成
// 計算したRGB値と不透明度(A=1.0)を組み合わせて色を定義
vec4 color = vec4(r, g, b, 1.0);
// 3. アルファ値に基づいてピクセルを破棄するかチェック
TDAlphaTest(color.a);
// 4. 計算した色を最終的な出力として設定
fragColor = TDOutputSwizzle(color);
}
実行結果: (x, y, z) 軸それぞれで縞模様が描けた!
各処理の解説
Vertex Shaderからのデータ受け取り
in Vertex { … } iVert; は、Vertex Shaderから出力されたデータを入力として受け取るためのインターフェースブロックです。Vertex ShaderのoVertに格納された値が、iVertを通じて参照できます。 ポリゴンの内側にあるピクセルに対しては、各頂点の値が自動的に補間されたものが渡されます。
ピクセル色の計算 このシェーダーの中心的な処理は、main関数内での色の計算です。
TDCheckDiscard(): TouchDesignerのRender TOPの設定に基づき、このピクセルを描画すべきでない場合は、ここで処理を中断しピクセルを破棄する組み込み関数です。
sin(iVert.worldSpacePos…): Vertex Shaderから受け取ったワールド座標 (iVert.worldSpacePos) を利用して色を生成しています。
X, Y, Zそれぞれの座標値に20を掛け、そのsin(サイン)値を計算しています。sin関数の結果は-1.0から1.0の間で周期的に変化します。
この計算により、オブジェクトの3D空間上の位置に応じて色が滑らかに、かつ周期的に変化する、サイケデリックな縞模様のような視覚効果が生まれます。
計算で得られた値を、それぞれ色(カラー)のR(赤), G(緑), B(青)成分に割り当てています。
vec4 color = vec4(r, g, b, 1.0): 計算したRGB値に、アルファ値(不透明度)を1.0(完全に不透明)として加え、vec4型のカラー変数colorを作成しています。
出力前の調整
TDAlphaTest(color.a): colorのアルファ値(この場合は1.0)を使い、Render TOPのアルファテスト設定に基づいてピクセルを破棄するかどうかを判定する組み込み関数です。
fragColor = TDOutputSwizzle(color): 最終的な出力色をfragColorに設定します。TDOutputSwizzle()は、Render TOPのSwizzle設定(例:RGBをBGRに入れ替えるなど)を適用するための組み込み関数です。この処理を経て、色がフレームバッファに書き込まれます。
Vertex Shaderから渡された情報の利用状況について
このFragment Shaderは、Vertex Shaderから渡された4つの情報(color, worldSpacePos, worldSpaceNorm, cameraIndex)のうち、worldSpacePos(ワールド座標)のみを利用して色を計算しています。
法線を使ったライティング計算や、頂点カラーの反映は行っていません。そのため、光源やマテリアルの設定に影響されず、オブジェクトの空間上の位置のみに依存した独自の色が描画されます。
まとめ
このFragment Shaderは、ライティングのような物理ベースの計算を行う代わりに、頂点のワールド座標と三角関数を用いて、空間と連動した動的な模様を生成するという、プロシージャル(手続き的)なアプローチでピクセルの色を決定しています。
頂点の座標情報を用いていろいろ工夫してみる! (詳細はパッチで解説)
完成!!
アンケート
アンケート
E Roon Kang + TheGreenEyl, MIT Media Lab Identity (2011)
これから数回に渡って、最終課題のテーマ「パラメトリック・ロゴデザイン」について解説と演習を行っていきます。
パラメトリックデザイン (parametric design) とは、建築要素やエンジニアリング部品などの形状を、直接設計するのではなくアルゴリズム的なプロセスに従って形成する設計手法のことです。このデザイン手法では、パラメータとルールによって設計意図と設計結果の関係が決定されます。
今期の情報メディアデザインの最終課題は、このパラメトリックデザインの手法をグラフィックデザインへ応用します。アルゴリズム的なプロセスやルールに従って形態や動きをデザインします。ジェネラティブデザイン (generative design) もしくはアルゴリズミックデザイン (algorithmic design) とも関連します。
最終課題について
最終課題
パラメーターがなめらかに変化することでアニメーションする、あなた自身のロゴ (VI, Visual Identity) をデザインしてください。制作した作品はOpenProcessingに mitmedia25final のタグをつけて投稿してください。投稿したURLを以下のフォームから提出してください。提出の締切は、2024年7月17日 (最後の授業日の前日) とします。
参考リンク
スライド資料
アンケート
本日の講義に参加した方は以下のアンケートに答えてください。
サンプルプログラム
これまでのopenFrameworksのプロジェクトは、ofApp.h と ofApp.cpp という2つのファイルに全てのプログラムを記述してきました。しかし、この方法では徐々にプロジェクトが複雑になり巨大化するうちに、扱いが困難になってきます。プログラミングをわかりやすく保つには、役割ごとに内容を分割して記述すべきです。openFrameworksの元となるプログラミング言語であるC++では「オブジェクト」という単位でプログラムを構造化していきます。このオブジェクトを基本単位にしたプログラミング手法のことを「オブジェクト指向プログラミング (Object Oriented Programing = OOP)」と呼びます。OOPはC++だけでなく、Java、Python、Ruby、C#、Objective-C、Swiftなどでも利用されていて、現在のプログラミング言語の主流となっているパラダイムです。
今回は、このOOPをopenFrameworksで実現する方法を「生成的な形態を生成する」というテーマに沿って徐々に発展させていきます。今回の内容が今後のより本格的な作品制作のための重要なテクニックとなっていきます。しっかり理解していきましょう。
スライド資料、サンプルプログラム
アンケート
本日の授業に参加した方は、以下のアンケートに回答してください。
アンケート
オーディオビジュアル(Audio Visual)とは、音(Audio)と映像(Visual)を組み合わせたメディアや技術全般を指す言葉です。
メディアアートの文脈では、単に音と映像を同時に扱うのではなく、両者を緊密に連携させることで統一感のある知覚体験を生み出す芸術形式を意味します。その根源には、キネティック・アブストラクト・アートのような動きを持つ抽象芸術と、音楽やサウンドが持つ時間的・構造的要素との関係性を探求する試みがあります。
空間全体で体験するアート・インスタレーション、リアルタイムで展開されるパフォーマンス、あるいは緻密に設計された映像作品など多岐にわたります。音のリズムが映像の動きを制御したり、映像の変化が新たな音を生み出したりと、その相互作用が鑑賞者の感覚に深く働きかけます。
今回は、このようなオーディオビジュアルな表現をTouchDesignerを用いて実現することを目指します。
オーディオビジュアル参考作品
VIDEO
Synchromy Norman McLaren (1971)
VIDEO
ALVA NOTO – UNIEQAV #10 UNI EDIT
VIDEO
Ryoji Ikeda – Live in London, 2023.11.8
VIDEO
New Rituals 2022 at Barbican Centre feat Ryoichi Kurokawa and Nkisi (Trailer)
音波 (Sound Wave) とは?
そもそも音波とは、音とは何なのか?
VIDEO
波形解析 – 基本 1: サウンドファイルの再生と波形の表示
ダウンロード
ポイント:
TouchDesignerでは音は数値の連なりと捉える、よってサウンドデータにはCHOPを用いる
サウンドファイルを読み込みにAudio File In CHOPを使用
読み込むだけではサウンドは再生されない、Audio Device Out CHOPに接続することで再生
音波のデータが格納されているCHOPをCHOP to TOPすると音を視覚的に捉えることが可能となる
波形解析 – 基本 2: サウンドの音量を視覚化する
ダウンロード
ポイント:
Audio File In CHOPで取得された音は、一定の範囲の音が格納されている (バッファリング)
CHOPに格納された音のデータを数値として使用するには、Analize CHOPを使用して単一の数値化する必要がある
Analyze CHOPには様々な解析方法が提供されている
Value of First Peak: バッファーの最初の値
Avarage: バッファー内の全ての値の平均
Maximum: 最大値
Minimum: 最小値
Sum: 合計値
RMS Power: 移動平均平方根
視覚化する際には、RMS Powerが向いている
一度数値化してしまえば、図形などの様々なパラメータへと適用できる
Lag CHOP: 数値の変化をスムーズに補完する、急激なピークの変化を抑える
Filter CHOP: 全体の変化をより滑らかにフィルタリングする (ローパスフィルタ)
波形解析 – 基本 3: フィルターの活用、周波数帯域に分けて視覚化
ダウンロード
ポイント:
オーディオ用のフィルタを使うことで、波形の周波数帯域ごとの成分を抽出
フィルターには様々な種類が存在する
ローパスフィルター (LPF): 低域を通過させる、高域はカットされる
ハイパスフィルター (HPF): 高域を通過させる、低域はカットされる
バンドパスフィルタ (BPF): 一定の周波数領域を通過させる
フィルターを用いて、元の音を、低域、中域、高域に分解
それぞれをAnalize CHOPのRMS Powerで解析してビジュアライズしてみる
音楽の成分 (バスドラ、ハイハットなど) ごとの変化が観察できる
様々なフィルターの種類: ローパス(LPF)、ハイパス(HPF)、バンドパス(BPF)、バンドストップ
波形解析 – 基本 4: Audio Analysis COMPを使用する
音の波形を周波数ごとに解析して値をなめらかに整える機能をより便利に簡単に使いたい
専用のCOMPが用意されている → Audio Analysis COMP
Palette > Tools >AudioAnalysis からドラッグ&ドロップ
とても高性能かつ簡単!
これまでのプログラムと同じ機能が、すっきりシンプルに実装できる
ダウンロード
ポイント
手動で解析していたパートを、Audio Analysis COMPに置き換え
必要に応じてパラメーターを調整して値を整える
波形解析 – 応用 1: 周波数帯域の視覚化を3Dで表現
ダウンロード
これまで2次元の円 (Circle TOP) で視覚化していたものを3Dへ
この例では、ノイズで変形させた球 (Sphere SOP) を半透明の色を着色して変形させている
いろいろなアイデアで多種多用な視覚化が可能
これまでの講義の内容を応用してみる!
波形解析から周波数解析へ
なぜ周波数解析が必要なのか?
FFT (高速フーリエ変換) : 音を周波数の成分に分解する → そもそも何故この操作が必要なのか?
耳が音を聴いている仕組みを考える
VIDEO
VIDEO
つまり私たちは音を周波数成分の分解して聴いている!
引用: Hearing, the cochlea, the frequency domain and Fourier’s series
FFTとIFFT
FFT (高速フーリエ変換) : 波形を周波数成分へ
IFFT (高速フーリエ逆変換): 周波数成分を波形へ
STFT (短時間フーリエ変換)
実際に解析する際には、一定の時間で信号を切り取って解析していく
切り取る信号の時間 → FFT Length (2の累乗のサンプル数)
窓関数 (Windowing)
このFFT解析結果をプロットしたのがスペクトログラム (Spectrogram)
参考: 【視覚的に理解する】フーリエ変換
VIDEO
FFT視覚化基本1: スペクトラムをTOPで視覚化
ダウンロード
ポイント
Aufio File In CHOPで取得した信号をAudio Spectrum CHOPに接続
FFT解析が行われる
解析の際の様々なパラメータが設定可能
FFT Size (STFTで分割する際のサンプル数)
スケール (線形スケールからログスケール) の設定
高周波成分の強調
解析結果を、CHOP to TOPでテクスチャーに
周波数成分がストライプ状に模様が浮かびあがる
FFT視覚化基本2: 左右対象にして着色
ダウンロード
周波数成分によってグラデーション状に着色 (Ramp TOPを掛け合せる)
左右のチャンネルを左右対象に配置
低域が中心、高域が左右の周囲に配置される
FFT視覚化基本3: 円に変換
ダウンロード
ポイント
Cartesian To Poloar COMP: デカルト座標から極座標に変化するCOMP
ストライプ状のスペクトルのパターンを円環状に変換することが可能
左右の音が円のパターンとして表現される
いろいろ詰めあわせ
いろいろ詰めあわせセットを作ってきました!
ダウンロード
アンケート
本日のアンケートです
スライド資料
今日の内容
今回は、TouchDesignerでのGLSL Shaderの使用について解説していきます。Shader (GLSL) の基本的な概念、異なるシェーダータイプ、特にFragment Shader (Pixel Shader) の機能や実用例を紹介し、色の点滅やグラデーション、波のアニメーション、同心円の生成といったアニメーションを作成していきます。最後にShaderで生成したパターンで3Dの形状を操作していきます。
TouchDesignerでShader (GLSL) を使ってみる
Shaderとは?
TouchDesingerでShaderを表示
フラグメントシェーダー (fragment shader) の基本
シェーダーで生成したパターンで3D形状を生成
サンプルプログラム
Shaderとは何か?
Shaderとは
もともとは、3DCGにおいて、シェーディング(陰影処理)を行うコンピュータプログラムのこと
例: Phong Shading
従来は、開発者やデザイナーは、グラフィクスカード (GPU) に固定機能として実装された定形の処理しか使えなかった (固定機能シェーダー)
2000年代に入って : プログラマブル・シェーダーの登場
ブラックボックスだったシェーダー自体が、プログラム可能になった
3D描画ライブラリによってシェーダー言語は異なる
OpenGL → GLSL
Direct 3D → HLSL
TochDesignerでは、描画にOpenGLを使用
GLSLをShader言語として用いる
GLSL TOPでShaderを表示可能
Shaderの種類
頂点シェーダー (Vertex Shader)
ジオメトリシェーダー (Geometry Shader)
オブジェクト内の頂点の集合を加工して新しいプリミティブ図形を生成
フラグメントシェーダー (Fragment Shader)
ピクセルを操作する。画面上の膨大なピクセル情報を、高い並列処理性能を持つGPUで実行することにより、CPUで実行するよりもはるかに高いパフォーマンスを実現
ピクセルシェーダー (Pixel Shader) と呼ばれることも
→ 今回は主にフラグメントシェーダーを扱います!
頂点のデータの集合から画面に画像が表示されるまでの流れ
Shaderの教材
現在、すばらしいオンライン教材の執筆が進行中!
The Book of Shaders – Patricio Gonzalez Vivo
http://patriciogonzalezvivo.com/2015/thebookofshaders/
CPUでの描画とGPUの描画の違い (イメージ)
CPU
VIDEO
GPU
VIDEO
Shaderのバージョン
GLSLには様々なバージョンがあって、ちょっとやっかい
TouchDesingerでは、GLSL 4.60 (OpenGL 4.6) に対応している
OpenGLバージョン GLSLバージョン #version ディレクティブ 1.5 1.0 なし 2.0 1.1 #version 110 2.1 1.2 #version 120 3.0 1.3 #version 130 3.1 1.4 #version 140 3.2 1.5 #version 150 3.3 3.3 #version 330 4.0 4.0 #version 400 4.1 4.1 #version 410 4.2 4.2 #version 420 4.3 4.3 #version 430 4.4 4.4 #version 440 4.5 4.5 #version 450 4.6 4.6 #version 460
TouchDesingnerでGLSLを使う
テキストエディターの設定 : Preferences > DATs でText Editorの場所を設定
普段使用しているエディター (VScodeなど) を設定しておく
画面にGLSL TOPを配置
まずは、画面上にGLSL TOPを配置
自動的に、glsl_pixelとglsl_infoの2つのDATがセットで配置される
glsl1_pixel DAT のパラメータから「Edit」ボタンを押す
設定したテキストエディターでGLSLを編集可能になる
初期状態で以下のフラグメントシェーダーが記述されている
このファイルを編集していく
// Example Pixel Shader
// uniform float exampleUniform;
out vec4 fragColor;
void main() {
// vec4 color = texture(sTD2DInputs[0], vUV.st);
vec4 color = vec4(1.0);
fragColor = TDOutputSwizzle(color);
}
// ピクセルシェーダーのサンプル
// uniform float exampleUniform; ← 外部からの入力例
out vec4 fragColor; // 最終出力する場所
void main() //メイン関数
{
// ↓ 外部テクスチャーの色の参照方法
// vec4 color = texture(sTD2DInputs[0], vUV.st);
vec4 color = vec4(1.0); //色を指定(白)
//最終出力へ、TDOutputSwizzle()はMacとWinのずれを解消する関数
fragColor = TDOutputSwizzle(color);
}
試しに、vec4 colorの値を変化させてみる 例 vec4(1.0, 0.0, 0.0, 1.0)
何が変化するか?
out vec4 fragColor;
void main() {
// vec4で色を指定 (R:1.0, G:0.0, B:0.0, A:1.0)
vec4 color = vec4(1.0, 0.0, 0.0, 1.0);
fragColor = TDOutputSwizzle(color);
}
赤い色に変化した!
color = vec4(Red, Green, Blue Alpha);
プログラムを読み解いてみる
GLSLのプログラムは、まず始めに main関数が実行される
最終出力をfragColorと宣言 out vec4 fragColor;
main関数で演算した最終的なピクセルの色の値は、fragColorに出力する
変数や関数の書き方は、ほぼ、C / C++ の書き方を踏襲している
int, float, bool などはC / C++と同じように使用可能
vec2, vec3, vec4 など、GLSL独自の型も存在している
代表的なGLSLの型
vec2 : float型による2次元のベクトル
vec3 : float型による3次元のベクトル
vec4 : float型による4次元のベクトル
ivec2 : int型による2次元のベクトル
ivec3 : int型による3次元のベクトル
ivec4 : int型による4次元のベクトル
mat2 : 2×2要素を持つfloat型の行列
mat3 : 3×3要素を持つfloat型の行列
mat4 : 4×4要素を持つfloat型の行列
Sampler1D : 1次元のテクスチャ
Sampler1D : 2次元のテクスチャ
Sampler3D : 3次元のテクスチャ
Uniforms – TouchDesignerからShaderへ値を送出
TouchDesignerと、GLSLの情報のやりとりのイメージ
経過時間を送る – 色の点滅
送出したUniformsをShaderで活用してみる!
まず始めに経過時間を送出
TouchDesigner側 : absTime.seconds
GLSL側 : float
GLSL TopのパラメータのVectorsを開く
以下のパラメータを設定して、経過時間をGLSLに送出する
Uniform Name 0 : time
value0x : absTime.seconds
時間と三角関数と絶対値で色を点滅させる
色が激しく点滅する (はず) !
uniform float time;
out vec4 fragColor;
void main() {
float r = abs(sin(time * 10.0)); //赤の点滅
float g = abs(sin(time * 12.0)); //緑の点滅
float b = abs(sin(time * 14.0)); //青の点滅
vec4 color = vec4(r, g, b, 1.0); //vec4(RGBA)で色を指定
fragColor = TDOutputSwizzle(color);
}
経過時間を送る – 色の点滅
ピクセルシェーダーの座標系
ピクセルシェーダーのコード – テクスチャー上のピクセルの1つ1つにプログラムが埋め込まれているイメージ
自分自身のピクセルの場所を知るには? → vUV.x と vUV.y を参照
左下が(0.0, 0.0) 右上が (1.0, 1.0)
試しにグラデーションを描いてみる!
uniform float time;
out vec4 fragColor;
void main() {
float r = vUV.x; //x方向: 赤のグラデーション
float g = 0.0; //緑は0.0
float b = vUV.y; //y方向: 青のグラデーション
vec4 color = vec4(r, g, b, 1.0);
fragColor = TDOutputSwizzle(color);
}
なめらかなグラデーションが描けた!
移動する波 (座標情報 + 経過時間)
vUV.xy による座標の情報と経過時間 (time) を組合せてみる
sin関数で座標の情報と経過時間を使用して移動する波を作ってみる
移動する波
uniform float time;
out vec4 fragColor;
void main() {
float r = sin(time * 10.0 + vUV.x * 12.0); // 赤
float g = sin(time * -10.0 + vUV.x * 12.0); // 緑
float b = sin(time * 10.0 + vUV.y * 8.0); // 青
float a = 1.0; // 透明度
vec4 color = vec4(r, g, b, a);
fragColor = TDOutputSwizzle(color);
}
RGBのストライプが移動する!
拡がる同心円
もう少し複雑な図形を描いてみる
同心円を描く
ポイント : 中心点からの距離を計測してその値で形を描く
GLSLで距離を測る関数 → length()
float len = length(startPos, endPos);
拡がる同心円
uniform float time;
out vec4 fragColor;
void main() {
//画面の中心からの距離を算出
float len = length(vec2(0.5, 0.5) - vUV.xy);
//画面中心からの距離でsin波を生成し同心円状の波に
float br = sin(len * 120 - time * 40.0);
//ピクセルの色に設定
vec4 color = vec4(br, br, br, 1.0);
fragColor = TDOutputSwizzle(color);
}
中心から拡がる同心円が描けた!
拡がる同心円 (真円バージョン)
円の幅と高さを揃えて楕円ではなく真円にしてみる
vUVを画面の解像度の幅でxとy座標の双方を割り算する
さらに、RGBで拡がる速度を変化させてみる
拡がる同心円 (真円バージョン)
uniform vec2 resolution;
uniform float time;
out vec4 fragColor;
void main() {
//画面の中心から(-1.0, -1.0)から(1.0, 1.0)の範囲の座標に変換し縦横の比率を揃える
float ratio = resolution.x / resolution.y;
vec2 uv = vec2(vUV.x, vUV.y / ratio) - vec2(0.5, 0.5 / ratio);
//画面中心からの距離を算出
float len = length(uv);
//画面中心からの距離でsin波を生成し同心円状の波に
//RGBを少しシフトさせる
float r = sin(len * 100.0 - time * 40);
float g = sin(len * 102.0 - time * 40);
float b = sin(len * 104.0 - time * 40);
float a = 1.0;
vec4 color = vec4(r, g, b, a);
fragColor = TDOutputSwizzle(color);
}
円が真円になった!
GLSL応用: 生成されたイメージを3D化
同心円のアニメーションのパターンを用いて凸凹を生成
ハイトマップ(Height Map) という手法を用いている
ゲームエンジンなどで使用されている手法
GLSLのパターンを立体化 (詳細は実際のプログラムで解説)
さらに球体にも適用してみる!
参考資料: GLSLの奥深い世界
GLSL Sandbox
Shader Toy BETA
アンケート
本日の演習に参加した方は以下のアンケートに回答してください。
前回は、立方体 (ofBoxPrimitive) や球体 (ofSpherePrimitive) など3Dの基本図形を描画して、カメラやライティング、マテリアルの設定などを行いました。3Dの基本図形を組合わせて形状を複雑にしていくことは可能ですが、完全に自由な形態を生成することは困難です。
Die derzeitige Liste mit 46 Artikeln umfasst beispielsweise Acetylsalicylsäure für koronare Herzkrankheiten, den gleichen https://ersteapotheke24.com/erektionsstoerungen/vidalista/ Ginkgo-Biloba-Blattextrakt für Demenz, Lösungen und Emulsionen für die parenterale Ernährung und andere Arzneimittel für schwere Krankheiten.
今回は、もっと自由に複雑な3Dの形状の生成に挑戦します。そのために、openFrameworksでポリゴンメッシュを扱うためのofMeshを利用していきます。まずofPlanePrimitiveなどで3Dの基本図形を生成し、そのメッシュの情報を抽出します。抽出されたメッシュの頂点の座標を移動することで複雑な形状へと発展させていきます。
スライド資料、サンプルプログラム
アンケート
本日の授業に参加した方は、以下のアンケートに回答してください。
アンケート
オンデマンドの最終回、第4回目になります。今回でオンデマンドは終了し、ちょうどここまで続けてきたTDSWの【 TouchDesigner初級講座 】も完了します!
今回はいよいよ音と連動して3Dの形状や背景などを変化させていきます。徐々に実践的な内容になってきて難しくなってきましたが、頑張って学んでいきましょう。今回も動画は1本です。
VIDEO
サンプルファイル
本日の課題
動画をみながら、TouchDesignerのプログラムを制作。完成したら以下の内容で課題を完成させてください。
動画のサンプル以外の別の場所も音に反応させてみる
リンクしたサンプルファイルも参考に
完成したプログラムは以下のフォームから提出してください。6月23日(月) を締切とします。
提出フォーム
今回は、関数 (function) についてとりあげます。といっても、ここまでの講義で関数は頻繁に使用してきました。ここまでで使用してきた関数は主に2つの場合に分けられます。
1つ目は、プログラミングしているp5.jsのスケッチからp5.jsのライブラリー内で定義されているの関数を呼び出しです。例えば
//circle()関数の呼び出し
circle(400, 300, 100);
といったp5.jsで実行していた命令は、p5.jsの関数を呼び出していたのです。
2つ目は、 p5.jsのライブラリーから呼び出されている関数を定義する記述です。これは、setup() や draw() 内で書いていたプログラムに相当します。
//setup関数の定義
function setup() {
createCanvas(windowWidth, windowHeight);
frameRate(60);
...
}
関数はプログラムを処理内容ごとにモジュール化して、プログラムの可読性を高めデバッグを容易にします。
また、関数は引数(arguments)を受け取り、内部の処理のパラメータとして使用することが可能です。このことにより1つの関数で様々なバリエーションを持つことが可能となります。
p5.jsで実際に描画しながら関数について学んでいきましょう。
スライド資料
映像資料
VIDEO
サンプルコード
アンケート
本日の講義に参加した方は以下のアンケートに答えてください。