jit.phys を2次元物理エンジンBox2d的に利用 #maxmsp #jitter

スクリーンショット 2014-09-04 17.15.30

2次元物理エンジン

Max6から導入されたjit.phys、デモなどをみると大抵3次元で利用されていますが、設定をすれば2次元でも利用できます。2次元物理エンジンで有名なBox2dみたいな使い方も可能というわけです。AZUMA HITOMIさんのVJでタイコマシーンの上に積み上がるボールは、これを使っています。

設定方法

スクリーンショット 2014-09-04 17.20.21
jit.phys.world のアトリビュート @remove_plane 3 と書くだけでZ軸を無視できます。

大量のオブジェクトを配置

スクリーンショット 2014-09-04 17.20.32
たくさんのオブジェクトを出したい場合は、jit.phys.multipleとjit.gl.multipleを使います。jit.phys.multipleが物理モデルの計算を担当し、表示をjit.gl.multipeが担当します。詳しくは、後述のコードで確認ください。

パフォーマンスは500個くらいまでなら60fpsで動いておりました。またオブジェクトのスケールを小さくしすぎると、物理計算が正しく行われなくなってしまうようでした。この辺りは注意して利用したいです。

デバッグ表示

スクリーンショット 2014-09-04 17.21.53

続きを読む jit.phys を2次元物理エンジンBox2d的に利用 #maxmsp #jitter

BPMに同期した映像の再生 #maxmsp #jitter

BPMに同期した映像の再生

スクリーンショット 2014-08-12 00.56.26
transportで指定したBPMとjit.qt.movieを同期させて、映像を再生する方法です。phasor~が指定したBar/Beatsでtransportに同期して0~1の信号を出すことができるので、その値をframecountに掛ける事で現在のフレームへジャンプさせて同期再生をする事ができます。例えば、2小節でjit.qt.movieの再生を繰り返したい場合は、phasor~のfrequencyアトリビュートに”2 0 0″と指定します。

続きを読む BPMに同期した映像の再生 #maxmsp #jitter

jit.gl.pix @gen によるシェーダ切り替えで画面が一瞬止まる問題について #jitter #maxmsp

スクリーンショット 2014-08-07 02.45.33

シェーダ切り替え

jit.gl.pixにて@genによるシェーダの切り替えを行うと一瞬画面が止まってしまう事案が発生いたしました。この原因は2つ考えられるかなと思いまして

  1. jit.gl.pixが内部的に.jitgen → .jxs / GLSLに変換してシェーダを使うため、SSDやHDDとファイルのRead/Write処理が同期的に行われて止まる
  2. GPU上へシェーダを転送・コンパイルする時に止まる

検証はできてないですが、1の方が原因としては重たそう。というのも、jit.qt.movieでreadするとファイル読み込みで画面が止まってしまう現象と同じなためです。jit.qt.movieではasyncread使うことで再生中の動画を止めずに切り替える事が可能ですね。ただ、実はこれも問題があり、大量のjit.qt.movieに対してasyncreadを指示すると画面止まります。内部的にどうやってるかコード読んでみたい。(関係ないけど、Windows版のMaxの非同期読込もサポートしてほしいな・・・。)余談はさておき、jit.gl.pixには非同期読み込みをするメッセージを送れません!

対処方法

BiLmv_hCUAEVOcq.jpg-largeパッチをロードしたタイミングで使いたいシェーダの数だけjit.gl.pixをインスタンス化しておく。使おうと思った時にはメモリ上に載っているので画面が止まる事は無さそうです。スマートなやり方ではないですが、この方法しかないかな・・・?使いたいシェーダの数が増えるとメンテナンスが大変になりそうなので、jsオブジェクトなどを使ってメタプログラミングでオブジェクトの自動生成をすれば、メンテナンスも楽そうです。やりすぎるとGPUのメモリが足りなくなる事案も発生しそうですが。

ちなみに上記画像は遠藤一郎氏のライブペインティングでプログラムしたときに使ったパッチのキャプチャです。音声ファイルを400個近く読み込む必要があって、ライブ中にファイル読込で止まるのが嫌だったので、起動時に全部メモリ上にロードしておくプログラムをjavascriptで書きました。

jit.gl.pix における2次元平面のアンチエイリアス処理 #maxmsp #jitter

jit.gl.pixでトランジションエフェクト

あのタグの次期バージョンに入れるトランジションエフェクトを開発しています。例えば、中央から丸が出てきて画面全体に広がるようなエフェクトをつくろうとすると、丸を書いて2つのテクスチャを割当るだけで簡単そうです。しかし、単純につくるとエッジがギザギザしてしまいます。そこでjit.gl.pix(フラグメントシェーダ)におけるアンチエイリアスを実装してみます。

アンチエイリアス処理有り

スクリーンショット 2014-08-10 03.08.23

アンチエイリアス処理無し

スクリーンショット 2014-08-10 03.13.37中央の円のエッジがギザギザしており、VJなどで大画面に表示するともっと気になるかなと思います。

円トランジションjit.gl.pix

スクリーンショット 2014-08-10 03.25.40現在のピクセルの半径rと、トランジションする円の半径rとの距離をとって、その距離が短い場合に(0~0.005の距離)smoothstepで補間をしています。補完した値でmixする事でエッジをなだらかに繋ぐ事が可能です。ここを単純に書くと大なり小なりで比較して、0 or 1ピクセルの色を指定して、switchやif文でピクセル値を切り替えて出力したくなりますが、それではエッジがギザギザになってしまいます。

jit.gl.model / jit.gl.shader を使って初音ミク(はちゅねみく)さんをメッシュに分解するエフェクト #jitter #maxmsp #glsl

メッシュ分解

スクリーンショット 2014-08-08 00.18.16ジオメトリシェーダを使ったエフェクトのテストです。メッシュが法線ベクトルの方向に飛んでいきます。Tell Your Worldで、もっとカッコよく使われていましたね。

Before はちゅねみくさん

スクリーンショット 2014-08-07 23.35.04

After はちゅねみくさん

スクリーンショット 2014-08-07 23.35.23モデルは、note.xさんで配布されているものを利用させて頂いております。実は、この処理は無理にシェーダでやらなくても、jit.genとjit.gl.mesh等々を使えば、CPU上でできたりします。

Before ちび初音ミク

スクリーンショット 2014-08-07 23.34.23

After ちび初音ミク

スクリーンショット 2014-08-07 23.34.26あれっデブミクさんになってしまった・・・メッシュが分解されて飛ぶ処理だと思っていたのですが、分解されてない?!処理を見なおさなければ。モデルは、モデモデさんで配布されているのを使わせて頂きました!

ジオメトリシェーダ

スクリーンショット 2014-08-07 23.41.14この画像では、元のはちゅねみくさんのモデルデータを保持しつつ、分解したトライアングルも描画しています。ジオメトリシェーダを使ってGPU上でメッシュの数を2倍にして表示するとできます。この処理はジオメトリシェーダらしいエフェクトと言えるかもしれません。

インタラクティブに音に反応


せっかくMax上で動作しているので、音に合わせてインタラクティブに変化させてみました。

JSX / GLSLコード

[html]
<param name="size" type="float" default="0." />
<language name="glsl" version="1.2">
<bind param="tex0" program="fp" />
<bind param="size" program="gp" />
[/html]
Maxのためのパラメーター、バインドの指定です。size変数でメッシュの位置を制御しています。tex0は、jit.gl.textureから渡されるテクスチャです。jit.gl.modelにjit.gl.shaderを適応した場合に、テクスチャをjit.gl.textureで別途設定してあげる必要があります。

Vertex Shader

[c]
#version 120

varying vec2 VTexCoord0;
varying vec3 VEyeNormal;
varying vec3 VEyeVertex;

void main()
{
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
VTexCoord0 = vec2(gl_TextureMatrix[0]*gl_MultiTexCoord0);
VEyeNormal = vec3(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
VEyeVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
}
[/c]
ほとんどジオメトリシェーダのための下準備しかしてないですね。

Geometry Shader

[c]
#version 120
#extension GL_EXT_geometry_shader4 : enable

uniform float size;

//VARYING
varying in vec2 VTexCoord0[3]; //[3] because this makes a triangle
varying in vec3 VEyeNormal[3];
varying in vec3 VEyeVertex[3];

//GLOBALFUNCTION
void main()
{
int i;
vec3 newVertex;

/*
//Pass through the original vertex
for(i=0; i<gl_VerticesIn; i++)
{
gl_Position = gl_PositionIn[i];
gl_TexCoord[0].st = VTexCoord0[i];
EmitVertex();
}
EndPrimitive();
*/

//Push the vertex out a little using the normal
for(i=0; i<gl_VerticesIn; i++)
{
newVertex = VEyeNormal[i] * size + VEyeVertex[i];
gl_Position = gl_ProjectionMatrix * vec4(newVertex, 1.0);
gl_TexCoord[0].st = VTexCoord0[i];
EmitVertex();
}
EndPrimitive();
}
[/c]
三角形プリミティブを受け取って、各頂点を法線方向にずらしてプリミティブを描画しています。なのでメッシュに分割するエフェクトじゃなかった(笑)ネギミクさんは法線ベクトルの値がプリミティブに垂直だから分解されているようです。コメントアウトされている所では、元のプリミティブを描画できます。

Fragment Shader

[c]
#version 120

uniform sampler2DRect tex0;

void main()
{
vec4 texel = texture2DRect(tex0, gl_TexCoord[0].st);
gl_FragColor = texel;
}
[/c]
テクスチャを引っ張ってきて色を付けているだけです。

おまけ ジオメトリシェーダ エフェクト その2

スクリーンショット 2014-08-07 17.20.20
ジオメトリシェーダにtriangleで入ってきたプリミティブをline_stripに変換するとこんな表現も簡単にできます。