1225

Twitter:@dn0t_ GitHub:@ogrew

VJAM vol.02 ニデテキタ。

年末最後のVJをしてきました。

otocara名義でのVJは久しぶり、ということでVJシステムをまるっと一新。

とはいえ、ぼくとつっしーの役割分担は相変わらず。

僕が基礎となる画を構成し、オーディオリアクティブなどで使うパラメータ調整をしつつ、それに対してつっしーがMIDIコンでポストエフエクトやら色調調整をいじいじする感じです。

半月程度の準備期間でやりたいことを詰め込んだ結果、全体的にだいぶ重めな処理が多くなってしまったのですが、toeファイルを

- オーディオ解析用
- 素材作成用 (.not用)
- ポストエフェクト用(つっしー用)

に分けたことでFPSは60をキープできました。

一方で反省点としては、

  • 画の焦点を下のほうに寄せてしまったので今回のようなScreen over DJスタイルだとわかりづらい。現場の写真は事前に共有されていたのでそこを踏まえてどういう展開にするか考えるようにする。

  • .notパートは2つの映像素材を合成する形で画作りをしていたけれどそれぞれUIが隣り合っていたため誤操作で意図しない画を変更してしまうケースが多発した。

  • セットアップ中MIDIケーブルが細くて小さいタイプのやつだったので暗闇でちゃんとPCに刺すことができず3分ほど汗が止まらなかった。

  • VJブースが次の人と隣り合わせの割と狭いスペースだったのでつっしーにはそこからズレた場所で頑張ってもらった。作業場所の事前確認と主催者への連絡をちゃんとする。

  • システムのUIの中に時計を入れ忘れたので、逐一スマホを開いて時間を確認してつっしーに伝達する係をやる羽目になった。

今回は金曜本番に対して日曜の夜には準備ができていたので平日のお昼休みに会社の会議室を占領して作戦会議をできたのでとても良かった。 つっしーはダンサーというのもあって音や空間に対する意識が高いので僕の作ったシステムや映像素材に対してのアドバイスや要望点は貴重かつ有益なものだった。プレイについては、実はNovation Circuitを秋に売ってしまったので、今回は倉庫にしまっていたnanoKONTROLを使ったのですが、ジェネ系であればこのくらいの機能・サイズ感で十分です。(何より軽い。)

KORG SLIM-LINE USB CONTROLLER nanoKONTROL BLACK

KORG SLIM-LINE USB CONTROLLER nanoKONTROL BLACK

  • 発売日: 2008/12/12
  • メディア: エレクトロニクス

ということで2020年もよろしくお願いします。イベント呼んでください。

togameさんの有機的なうにょうにょしたVJじっくりみれて良かったです。(猫の両目のズームみたいな素材が印象的です。)

俺はグレイスケールがわからない。

f:id:taiga006:20191117191204j:plain

どうも、0kawaraです。

この記事はTouchDesignerのAdvent Calender 2019の12/23分の記事となります。

昨日は@satoruhigaさんの「TouchDesignerのパフォーマンス測定」でした。Probeはよく使っていましたが、最初のGeometry COMPでtransformしたほうがただtransform CHOPを使用するよりパフォーマンスが良いというのは知りませんでした。参考になります。

さて、去年のTouchDesignerのアドレカでは私はこの記事を書きました。あれからもう1年なんですね。

さて、今年のアドレカは小ネタです。というのも12月の暇な時間はほとんど先週参加させていただいたVJAM Vol.2の準備に費やしてしまったからです。ごめんなさい…。

言い訳が済んだところで早速内容に入っていきたいと思います。

今回はグレイスケールの話を少しさせていただこうと思います。

GLSLでグレイスケールさせるのには

(color.r + color.g + color.b) / 3.0

した値を使えばとりあえず良いというのは御存知の通りかと思います。

そして、ただこれを計算しても良いけれど、少し賢い書き方として

dot(color.rgb, vec3(1.0/ 3.0))

と書く方法があるのを先日のGLSLスクールで師匠doxas氏に教わりました。

さっそく書いて見るわけです。

// simple gray scale

out vec4 fragColor;
void main()
{
    vec4 color = texture(sTD2DInputs[0], vUV.st);
    float gray = dot(color.rgb, vec3(1.0/ 3.0));
    color = vec4(vec3(gray), 1.0);
    fragColor = TDOutputSwizzle(color);
}

f:id:taiga006:20191117203809j:plain

よしよし、「グレイスケール完全に理解した…2020年もみなさま、よろしくね」と。

…そういえばTouchDesignerにはmonochromeTOPという便利なものがあるのでそれと差分を確認して終わりましょう。

そして「あれれ?」となったわけです。 うっすらと差分があることに! Levelオペレータを使って差分をより見やすくしたものを載せます。

f:id:taiga006:20191117203540j:plain

(下が先程グレイスケール化したもの。上がmonochromeTOPとの差分を見やすくしたもの。)

おうおうおう。

そういえばGLSLスクールのときにdoxas先生が「グレイスケールは沼」みたいなことを言っていたなと思い出しました。

そのとき紹介していたのがこちらの記事なのですがちょっと無知には長くて難しすぎるので一旦別のサイトを転々としてみました。(え。)

そして、まず「NTSC加重平均法」というものに出会います。

なにやら人間の目が感じるRGBのバランスを考慮して荷重を加えて変換する方法がいくつかるようです。

そ、そんなのが…。

ということで実装してみます。(といっても補正定数で決まっているので置き換えるだけですが…。)

// NTSC(BT.601)

out vec4 fragColor;
void main()
{
    vec3 colormatrix = vec3(0.298912, 0.586611, 0.114478);

    vec4 color = texture(sTD2DInputs[0], vUV.st);
    float gray = dot(color.rgb, colormatrix);
    color = vec4(vec3(gray), 1.0);
    fragColor = TDOutputSwizzle(color);
}

先程同様monochromeオペレータとの結果を比較してみると、今度はほとんど差分がありません。でも、完全になくなったわけでもなさそうです。小数点の扱いによる誤差が考えられます。

f:id:taiga006:20191117203337j:plain

他にも、HDTV規格用の係数を利用するケースも有るようです。 これは先程より計算がわかりにくいですが、また別の補正値を導入して計算します。

// HDTV(BT.709)

out vec4 fragColor;
void main()
{
    vec3 colormatrix = vec3(0.222015, 0.706655, 0.071330);
    vec4 color = texture(sTD2DInputs[0], vUV.st);

    float p = 2.4;
    float r = pow(color.r, p) * colormatrix.r;
    float g = pow(color.g, p) * colormatrix.g;
    float b = pow(color.b, p) * colormatrix.b;

    float gray = pow(r + g + b, 1/p);
    color = vec4(vec3(gray), 1.0);
    fragColor = TDOutputSwizzle(color);
}

f:id:taiga006:20191117203412j:plain

PhotoShopのグレースケール化にはこれが使われているそうです。 p = 2.4の結果を載せています。この補正値をどう置くかでだいぶ結果が変わってきます。

(ちなみにここまで出てきたBTというのはこれらの色域を使ったテレビ放送用の規格のことを指すようです。)

また、上記2つの方法で用いた係数からわかるように心理的に6,7割がRGBのGに左右されるのであればGだけで計算するという大胆な方法もあります。

// only G channel

out vec4 fragColor;
void main()
{
    vec4 color = texture(sTD2DInputs[0], vUV.st);

    color = vec4(vec3(color.g), 1.0);
    fragColor = TDOutputSwizzle(color);
}

f:id:taiga006:20191117203625j:plain

だいぶ大胆ですが、今回サンプルとして使用した画像がクリスマスツリーだったというのもあって、ほとんど違和感のないグレイスケールが手に入りました。(monochromeTOPとの差分はこれまでで一番大きいことがわかります。)

(MEMO:後もう一つ実験してみたいことができたので、ここに追記する。)

ここまでの結果を一覧にしてみます。

f:id:taiga006:20191117203719j:plain

※念の為ですが、monochromeTOPとの差分の部分は見やすくするためにLevelTOPでコントラストを上げたりして調整しています。手元の環境で試していただければわかりますが、実際目に見える差分はもっと小さいです。あしからず。

最後に、NTSCを使ってグレースケール化したものをセピア色に変えてみましょう。 こちらも簡単です。

// sepia

out vec4 fragColor;

void main()
{
    vec4 color = texture(sTD2DInputs[0], vUV.st);
    vec3 ntsc = vec3(0.298912, 0.586611, 0.114478);
    float v = color.r * ntsc.r + color.g * ntsc.g + color.b * ntsc.b;

    color.r = v * 1.07;
    color.g = v * .74;
    color.b = v * .43; 

    fragColor = TDOutputSwizzle(color);
}

f:id:taiga006:20191117195233j:plain

以上です。

明日は@hideki_eguchiさんの「TOP1つで簡単に作れるクレイジーなGlitchについて書く予定です。」です。え~~~、そんな魔法があるの~。明日も目が離せない~~。

参考文献

k75thunderbird.hatenablog.com

wgld.org

ofo.jp

qiita.com

EEVEEでトゥーンレンダリング

先に結果です。

f:id:taiga006:20191214212609p:plain

前からやってみたいやってみたいと思いつつ、やれていなかったトゥーンシェーダー(あるいはセルルック、セルシェーダー)をblenderのマテリアル芸で実現する方法を学習しました。基本的には最後にまとめた参考サイトを写経した感じになりますが、学びがあったのとやっただけだとどうせ忘れてしまうので記録として残しておきます。

①View Transformの変更

2.8系からデフォルトのColor ManagementのView Transformが"Filmic"になっている。"Filmic"はよりフォトリアルっぽい表現を実現するが今回の場合はむしろその逆なので、これを"Standard"に変更します。

②コンタクトシャドウをON

これはいまいちまだよくわかっていないのですが、Lightの設定からこれをONにしておくとオブジェクト間の細かな部分での影を表現することができます。

③マテリアルシェーダーを組む

f:id:taiga006:20191214220336p:plain 一番メインのところですが、意外とシンプルです。

まず、基本的な陰影の2値化を一番左のパートでつけています。(Shadowパート)

ちなみに、ここのRGBを別で作ったテクスチャにすればより表現の幅が広がります。

そしてFrenelパートですが、まずFrenel(反射、効果)とはなんなのでしょうか?

たとえばある球体を見るときの入射角がより垂直に近いと反射が弱いので光沢があまりないのに対して、反対に球体の外側(入射角が平衡に近い方)にいくほど反射が強まり結果光沢が出てツヤがあるように見えるという現象

みたいな認識です。ちょうど前にブログでも紹介した「HOW TO RENDER」にそんなことが書いてありました。 今回はそのノードを利用して2値化することで一旦物体のアウトラインを作ります。

そして次に最初のShadowパートをもう一度、今度は狭い範囲でかけてハイライトを描きます。(Highlightパート)

最後にFrenelを使って最終的なアウトラインを黒く描きます。ただしこの時点ではアウトラインはうまく描けません。モディファイアを使って調整をします。

④Solidifyモディファイアをかける

f:id:taiga006:20191214222143p:plain オブジェクトに対して Solidifyモディファイアをかけます。このときThicknessをマイナス、Normalsを反転させます。

⑤アウトライン用のマテリアルを追加

f:id:taiga006:20191214221100p:plain 先程組んだマテリアルとは別に上のようなマテリアルを作成します。 このときマテリアルのSettingsからBlend Modeを"Alpha Blend"にしておく必要があります。

これできれいに黒いアウトラインを描けるようなりました。(太さも先程のThicknessで変えられます。)

※この最後にやったバックフェイスを使ったアウトラインの描く方法を背面法と一般に読んでいるそうです。

そもそもアウトラインを描くのであればFreeStyleの機能を使うこともできますが、レンダリング結果にしか反映されないので細かな調整に時間がかかった印象です。

以上、EEVEEでのトゥーンレンダリングについてまとめましたが、これがCyclesでやるとなるとまた少し制限があるようです。

また、今回はマテリアルそのものを使って表現しましたが、コンポジティングでやるという方法も別であるようです。

www.youtube.com

ちょっと前にTwitterで見かけたこの手法も今度挑戦してみたいと思います。

それからトゥーンレンダリングについてはアドオンを買ってしまうというのも手として十分にあります。

blendermarket.com

これなんか良さそうです。

参考

mororin.com

dskjal.com

tama-chan.jp

bintololab.com

あずかり知らぬ何ものか

ポストに漫画が刺さっていた。 そういえば随分前に注文した漫画だ。 それと積ん読したままだった漫画を1冊持って近所の喫茶店に向かった。 ポイントカードが導入されていたが店員に勧められなかったので作らなかった。 この手のカードは一度機会を逃すとどんどん損をした気持ちになって二度と作れなくなるというかまいたちのコントを思い出した。

ミッドナイトブルー (フィールコミックス)

ミッドナイトブルー (フィールコミックス)

須藤祐実さんの漫画は他に知らないのだけれど表紙の絵の女の子が気に入って買った。 どんぴしゃの内容だった。短編集だけどそのどれもが切なくて、真っ直ぐな話だった。 「ある夫婦の記録」という編が気に入っている。奇しくも主人公夫婦の名字が”大河原”だった。 最後の表題作でもある「ミッドナイトブルー」も良かった。 話はぜんぜん違うがなぜか青山剛昌の短編集にあった「ちょっとまってて」を思い出した。 あれも非常にいい短編集だったな、中古でもいいのでまた読みたい。

水は海に向かって流れる(2) (KCデラックス)

水は海に向かって流れる(2) (KCデラックス)

「水は海に向かって流れる」は2019年、買ってよかった漫画3本の指に入る。間違いなく。 その2巻だ。発売をずっと待っていた。派手な演出もなければ感動する、というのとも違う。 全員がいい人で、ひとつのできごとをきっかけにちょっとずつみんな気まずい。 でも、少しずつ前にむこうとしている。柔らかいタッチとときどきハットさせられるようなセリフ。 それが好き。

#nodevember2019 を振り返る。

この記事はBlender Advent Calendar 2019の3日目の記事です。


先週末、Motion Plus Design Tokyo 2019に行ってきました。

ASH THORPが"Be Prolific"って言ってましたね。2020年もたくさん作っていきましょう!

さて、今年ぬるっと初参加した #nodevember2019 の作品を振り返っていきたいと思います。 (作成したノードもスクショでシェアします。) さまざまなアーティストが公開している作品や動画を参考にしている(当初まとめて公開する予定もなかった)ので申し訳ありませんがリファレンスは今回まとめていません。 気になる方は上のハッシュタグでぜひ検索してみてください。

What is #Nodevember?

f:id:taiga006:20191130211744p:plain:w500

(↑ この間のカヤックの「つくっていいとも」で使った発表資料。) 要は11月のお祭りですね!

それでは早速見ていきましょう。

11/8 Coral

f:id:taiga006:20191130213038j:plain:w500

Node

f:id:taiga006:20191130223306p:plain:w500

11/9 Microbe

f:id:taiga006:20191130211947j:plain:w500

Node

f:id:taiga006:20191130222922p:plain:w500

11/19 Circuit

f:id:taiga006:20191130222516p:plain:w500

Node

f:id:taiga006:20191130222326p:plain:w500

11/19 Circuit(2)

f:id:taiga006:20191130222411p:plain:w500

Node

f:id:taiga006:20191130222212p:plain:w500

11/22 Star

f:id:taiga006:20191130212027j:plain:w500

Node

f:id:taiga006:20191130223840p:plain:w500

11/22 Star(2)

f:id:taiga006:20191130224138j:plain:w500

Node

f:id:taiga006:20191130224058p:plain:w500

11/24 Nebula

f:id:taiga006:20191130211922j:plain:w500

Node

f:id:taiga006:20191130220514p:plain:w500

もう一個くらいやっておきたかったかな。


とてもたくさんの作品が1ヶ月の間で作成されシェアされ盛り上がりました。 私がファンになったアーティストたちを紹介します。

TouchDesignerで画像処理シェーダー。その2

f:id:taiga006:20191124163637j:plain さっそく第二弾。

今回は、先日無事終わったGLSLスクールで学んだものとよく使うテクスチャいじりのものを載せておきます。

★RGBずらし

f:id:taiga006:20191124023459j:plain

// RGB shift
uniform vec2 offset;

out vec4 fragColor;

void main()
{
    vec2 coord = vUV.st;
    vec4 color = texture(sTD2DInputs[0], coord);

    vec4 negColor = texture(sTD2DInputs[0], coord + vec2(-offset[0], 0.0));
    vec4 posColor = texture(sTD2DInputs[0], coord + vec2(offset[1], 0.0));

    fragColor = TDOutputSwizzle(vec4(negColor.r, color.g, posColor.b, color.a));
}

ちなみに色収差とRGBずらしは正しくは同じものではないとのこと。(同じだと思ってた。)

★クランプ

f:id:taiga006:20191124023442j:plain

// clamp
uniform float clampMin;
uniform float clampMax;

out vec4 fragColor;

void main()
{
    vec2 coord = clamp(vUV.st, clampMin, clampMax);
    vec4 color = texture(sTD2DInputs[0], coord);

    fragColor = TDOutputSwizzle(color);
}

clamp関数はclamp(x, min, max)で最大最小を制御するものです。

★拡縮

f:id:taiga006:20191124142441j:plain

// scaling
out vec4 fragColor;

void main()
{
    vec2 newUV = 6.0 * vUV.st;
    vec4 color = texture(sTD2DInputs[0], newUV);

    fragColor = TDOutputSwizzle(color);
}

基本的なやつです。よく使います。ここではInput Extend Mode UVをMirrorに変えています。

★テクスチャゆがみ

f:id:taiga006:20191124154234j:plain

// distortion
uniform float scale;
uniform vec2 center;

out vec4 fragColor;
void main()
{
    vec2 direction = vUV.st - center;
    vec2 coord = vUV.st + scale * normalize(direction);
    vec4 color = texture(sTD2DInputs[0], coord);

    fragColor = TDOutputSwizzle(color);
}

centerからの方向に対してスケールさせることでゆがみを演出しています。scaleの正負を変えるとだいぶ印象が変わります。

★溶解

f:id:taiga006:20191124160227j:plain

// melt
uniform float time;

out vec4 fragColor;

void main()
{
    vec2 coord = vUV.st;
    
    vec2 melt = vec2(coord.x, coord.y*0.15+time*0.1);
    vec3 meltTex = texture(sTD2DInputs[0],melt).rgb;
    meltTex = melttex / 10.0;
    coord = coord.xy - meltTex.xy;
    vec4 color = texture(sTD2DInputs[0], coord);
    
    fragColor =TDOutputSwizzle(color);
}

1つのテクスチャだけでやっていますが別の画像やノイズをInput[1]に入れて使うともっと面白くなります。

へこみ

f:id:taiga006:20191124163519j:plain

// dent
uniform vec2 width;
uniform vec2 center;

out vec4 fragColor;
void main()
{
    vec2 coord = vec2(2.0) * vUV.st - vec2(1.0); // -1 ~ +1

    vec2 s = sign(coord);
    coord = abs(coord);
    coord = coord * (1. + smoothstep(width.x, width.y, coord + center));
    coord = 0.5 * s * coord;
    coord = coord / 2.0 + 0.5;

    fragColor = texture(sTD2DInputs[0],coord);
}

Paletteの中にあるdentに少し手を加えたものです。これもよく使いますね。

TouchDesignerで画像処理シェーダー。その1

f:id:taiga006:20191121133229j:plain

シリーズ化を宣言することで続けていかなければならないカルマを背負う。

今日はICSさんの記事にあったWebGLの簡単な画像処理をTouchDesignerでも使えるGLSLに。

★モノクロ

f:id:taiga006:20191121133817j:plain

// monochrome

out vec4 fragColor;

void main()
{
    vec4 color = texture(sTD2DInputs[0], vUV.st);
    float gray = dot(color.rgb, vec3(1.0/ 3.0));
    color = vec4(vec3(gray), 1.0);

    fragColor = TDOutputSwizzle(color);
}

(r,g,b)とvec3(1/3)の内積を取ることが平均になるところがポイント。

★ネガポジ反転

f:id:taiga006:20191121133352j:plain

// reversal

out vec4 fragColor;

void main()
{
    vec4 color = texture(sTD2DInputs[0], vUV.st);

    vec3 reversalColor = vec3(1) - color.rgb;
    color = vec4(reversalColor,1.);

    fragColor = TDOutputSwizzle(color);
}

シェーダーで使われるrgbは0.0~1.0なので反転させるには1.0から引けば十分です。

★モザイク

f:id:taiga006:20191121133555j:plain

// mosaic

uniform vec2 res;
uniform float mosaicScale;

out vec4 fragColor;

void main()
{
    vec2 mUV = floor(vUV.st * res / mosaicScale)  / (res/ mosaicScale) + (mosaicScale/2.) / res;
    vec4 color = texture(sTD2DInputs[0], mUV);

    fragColor = TDOutputSwizzle(color);
}

強引に1行にまとめました。 mosaicScaleで縦横分割した何ブロック目にいるのか、そしてそのブロックの中央のピクセルを見て色を決めます。

★すりガラス

f:id:taiga006:20191121133439j:plain

// glass

uniform vec2 res;
uniform float time;

out vec4 fragColor;

float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

void main()
{
    vec4 color = texture(sTD2DInputs[0], vUV.st);

    float r = 7.;
    float x = (vUV.s * res.x) + rand(vUV.st) * r * 2. - r;
    float y = (vUV.t * res.y) + rand(vUV.ts) * r * 2. - r;

    color = texture(sTD2DInputs[0], vec2(x,y) / res);

    fragColor = TDOutputSwizzle(color);
}

ある一定の距離感覚の範囲の中からランダムでピクセルの色を取得しています。

★2値化

f:id:taiga006:20191121133512j:plain

// threshold

uniform float threshold;

out vec4 fragColor;

void main()
{
    vec4 color = texture(sTD2DInputs[0], vUV.st);

    float v = dot(color.rgb, vec3(1.0/3.0));
    if (v >= threshold) {
        v = 1.0;
    } else {
        v = 0.0;
    }

    fragColor = TDOutputSwizzle(vec4(v,v,v,1.0));
}

モノクロの応用です。と言ってもある閾値を設けてそれ以上であれば白、未満なら黒にするだけです。

★ランダムディザー

f:id:taiga006:20191121133634j:plain

// random dithering

uniform float threshold;

out vec4 fragColor;

float rand(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

void main()
{
    vec4 color = texture(sTD2DInputs[0], vUV.st);

    float v = dot(color.rgb, vec3(1.0/3.0));
    if (v >= rand(vUV.st)) {
        color.rgb = vec3(1.0);
    } else {
        color.rgb = vec3(0.0);
    }

    fragColor = TDOutputSwizzle(color);
}

先程作った2値化の閾値自体をランダムに決めるというものです。


ics.media

HOW TO RENDERを読んだ。

f:id:taiga006:20191120184346j:plain

オフィスが鎌倉から秋葉原になってから会社の本棚というものをよく見るようになった。鎌倉のときは良くも悪くもほとんど事業部ごとに各ジャンルの専門書籍がまとまっていた。一方で秋葉原のオフィスはすべての書籍が一箇所にまとまっており、それこそ最近の漫画から今日紹介するような専門書まで追いてあり背表紙を眺めているだけでも興味深い。

さてスコットロバートソンといえば”HOW TO DRAW”が有名だと思うが(専門外の自分でも聞いたことがあったので)、今回読んだのは”HOW TO RENDER”。まえがきに当たる部分で「この本は”HOW TO DRAW”の続きにあたる」といったことが書かれてる。実はまだ”HOW TO DRAW”を読んだことはないのだけれど(え?)、ざっと立ち読みして面白そうだったので借りて読んでみた。

読んでみて、たしかにこの書籍はアーティスト(特に3Dオブジェクトを2Dで表現する人たち)に向けた専門書の位置づけというのが相応しい内容で具体的には光や影、そして反射といった様々な自然の中の事象ごとに、ドローイングされたものをよりリアリスティックに表現し、それを見る人(主に非アーティスト)に対しての視覚言語の意味合いをより強く裏付ける手法として、実際の物理的な側面から学ぶと言ったものだった。

また、自分のようなエセ3D芸術家ごっこをしている人間でもちょっと学びはあった。特に反射、光沢あたりのパートはいわゆるアーティストと言われる人間でなくても日常の観察眼としてモノを見るときの楽しみ方をより豊かにしてくれるような内容だった。ところどころ翻訳がうまく言っていないようなところが見受けられたがそこまで気にするレベルのものでもなかった。

そして、これは特にアーティスト向けのコンテンツとなるが、この書籍(そしてどうやら”HOW TO DRAW”のほうも)には専用のアプリがありそれをダウンロードすると専用のカメラツールが立ち上がり本書内の各スケッチにそれをかざすとスケッチの様子の解説動画が再生されるようである。

自分は特にやろうとは思わないが、実際に手を動かして学ぶこともできるという意味で非常に教育向けの本であることは間違いないと言える。

さて、次は何を借りてみようかなー。

自分の好きなGlitchを考える。

glslスクールでせっかくグリッチを教わったのでその話です。
スクールで教わったグリッチはモザイク化(ブロックで分割して解像度を下げる)してからランダム値を返す関数を使ってテクスチャをずらしてグリッチをかけるというものでした。

まず横方向のみだったサンプルを拡張して縦横両方向にずれるようにします。

out vec4 fragColor;
uniform vec2 resolution;
uniform float time;
uniform float threshold;
uniform vec2 blockSize;

float rnd(vec2 n){
    float a = 0.129898;
    float b = 0.78233;
    float c = 437.585453;
    float dt= dot(n ,vec2(a, b));
    float sn= mod(dt, 3.14);
    return fract(sin(sn) * c);
}

void main()
{
    float blockV = blockSize[0];
    float blockH = blockSize[1];
    float Vert = floor((vUV.t) / blockV) * blockV;
    float Horz = floor((vUV.s) / blockH) * blockH;

    // 0.0 ~ 1.0のランダムな結果を返す
    float gNoiseV = rnd(vec2(Vert, time*.1));
    float gNoiseH = rnd(vec2(Horz, time*.2));
    // thresholdを基準に0 or 1を返す
    float gStepV = step(gNoiseV, threshold * 2.);
    float gStepH = step(gNoiseH, threshold);
    // ズレの強度を決める
    float gStrengthV = gNoiseV / threshold;
    float gStrengthH = gNoiseH / threshold;
    // -1.0 ~ 1.0の間に補正する
    gStrengthV = gStrengthV * 2.0 - 1.0;
    gStrengthH = gStrengthH * 2.0 - 1.0;

    float V = gStepV * gStrengthV;
    float H = gStepH * gStrengthH;

    vec2 coord = vUV.st + vec2(V + H, 0.0);
    vec4 color = texture(sTD2DInputs[0], coord);

    fragColor = TDOutputSwizzle(vec4(color.rgb, 1.0));
}

ex1)

threshold -> 0.1
blockSize -> [0.6, 1.0]

f:id:taiga006:20191111154628g:plain

ex2)

threshold -> 0.3
blockSize -> [0.4, 0.02]

f:id:taiga006:20191111155037g:plain

パラメータでだいぶ結果が変わります。いい感じです。
ただもう少し元絵に動きを加えて不安な感じ?にしたいなぁと思いました。
参考文献を見て三角関数でテクスチャにオフセットを足すといい感じになりました。

out vec4 fragColor;
uniform vec2 resolution;
uniform float time;
uniform float threshold;
uniform vec2 blockSize;
uniform vec2 length;
uniform vec2 width;
uniform vec2 speed;

float rnd(vec2 n){
    (...省略...)
}
// Offsetといっても結局ただの時間依存のsin波を返すだけ
float calcOffset(float pos, float length, float width, float speed) {
    return sin(pos * length + mod(time, 3.0) * speed) * width;
}

void main()
{
    float blockV = blockSize[0];
    float blockH = blockSize[1];
    (...省略...)
    float V = gStepV * gStrengthV;
    float H = gStepH * gStrengthH;

    float offsetX = calcOffset(vUV.s, length[0],width[0],speed[0]);
    float offsetY = calcOffset(vUV.t, length[1],width[1],speed[1]);

    vec2 uv = vec2(vUV.s + offsetX, vUV.t + offsetY);

    vec2 coord = uv + vec2(V + H, 0.0);
    vec4 color = texture(sTD2DInputs[0], coord);

    fragColor = TDOutputSwizzle(vec4(color.rgb, 1.0));
}

ex3)

threshold -> 0.05
blockSize -> [0.5, 0.05]
length -> [12, 8]
width -> [0.003, 0.005]
speed -> [32,18]

f:id:taiga006:20191111202818g:plain

参考

https://nogson2.hatenablog.com/entry/2018/01/19/002342nogson2.hatenablog.com

relbboxってなんやねん、という話。

つまりは

ジオメトリの境界ボックスを基準に、指定したポイントの相対位置を返します。

ということらしい。基本的には

vector  relbbox(<geometry>geometry, vector position)

この構文。

geometryは何番目のインプット?のgeometryかって指定だから最初のうちは0とかせいぜい1しか使わない。そのgeometry内でのpositionの相対位置(つまり0~1)を返す。 ちなみにgeometryの指定は飛ばすことができるみたいで

vector  relbbox(vector position)

って書くこともできる。(ただしこの形式は今後消される可能性あり。)

ちなみにExpression記法?として

$BBX = relbbox(@P).x
$BBY = relbbox(@P).y
$BBZ = relbbox(@P).z

と同義らしい。

ex1) Y座標の相対的な大きさに比例してX座標をずらす。(→加算)

@P.x = @P.x + relbbox(0, @P).y * ch("strength");

f:id:taiga006:20191106222418p:plain

ex2) Y方向の相対的な大きさに比例してXZが広げる/細める。(→乗算)

@P.x = @P.x * pow(ch("strength"), relbbox(0, @P).y);
@P.z = @P.z * pow(ch("strength"), relbbox(0, @P).y);

f:id:taiga006:20191106222932p:plain ※strengthの値を1以下にすれば先端はとがる。

ex3) Y座標の相対的な大きさに比例してXY平面を曲げる。

float bby = relbbox(@P).y;
@P.x = @P.x * cos(radians(bby * ch("strength"))) - @P.y * sin(radians(bby * ch("strength")));
@P.y = @P.x * sin(radians(bby * ch("strength"))) + @P.y * cos(radians(bby * ch("strength")));

f:id:taiga006:20191106224300p:plain

ただ結局
relative + box ?
rel +b? + box ?
わからないままである。