Renard's Blog

かきます

VJ ゆるWriteup (VRChat Sequence 16 2023-12-18)

VJ ゆるWriteup (VRChat Sequence 16 2023-12-18)

こちらはジェネ系VJ Advent Calendar 2023の18日目の記事です

qiita.com

要約

  • GLSL(Fragment Shader)だけでジェネVJした

はじめに

VRChatのクラブイベント「Sequence」でVJをしました

使ったもの

構成

全体の構成はこれだけです
TDは動画をNDIで飛ばす装置として使いました

構成

Sh4der Jockey側のパイプラインはこんな感じです
GはIncludeして使いまわすやつで、Fがfragment本体

パイプライン

uvmapがこんな感じだったので、真ん中に出力するの(mainout)と横の二つ(subout)に分けました

uvmap

なんか

SDXLでフッテージ作る

TDからNDIで送るフッテージはSDXLで作りました

ComfyUIを使いました

こんな感じでノードで使えるので、Automatic1111よりやりやすいです

動画作るのはこれでやりました 他にもいろいろ入れたけど

github.com

一つの動画が3.875秒なので、pixelsortで無理やり32個つなげたのを作りました

駅のホーム
女の子

せっかくなので共有します

drive.google.com

1024x1024で長さ2:04です pixelsortのタイミングも同じなので、重ねられます

入力について

Akai midi mixと適当なゲームパッドでやりました

Sh4der Jockey側で入力を受けるのですが、MDI以外は受けられないのでゲームパッドを仮想MIDIに変換しました

やり方↓

触手のイージング

触手の動きはこんな感じです

float tr=1-exp(-time*5);
tr+=(.5-.5*cos(TAU*tr))*.5;

初速大きめに動き過ぎて、ちょっと戻る感じ

graphtoy.com

感想

  • 楽しかった
  • loserさんのDJについていくのが難しかったので、次はもっとうまくやりたい
  • ストロボ最強

VJ ゆるWriteup (VRChat WIREDVEIN 2023-12-01)

VJ ゆるWriteup (VRChat WIREDVEIN 2023-12-01)

こちらはジェネ系VJ Advent Calendar 2023の5日目の記事です

qiita.com

まだ参加者が少ないのでもっと皆さんに書いて欲しい~~

要約

  • UnityHDRPでジェネVJやったよ

はじめに

VRChatのクラブイベント「WIREDVEIN」でVJをしました

動機

  • UnityHDRPのレイマーチングシェーダーを新しいHDRPに対応させたい

イメージ/やりたいこと

  • レイマーチングでピカピカする

  • 顕微鏡で内臓を見る (見るとこはコントローラーで動かせる)

顕微鏡

実装/知見

レイマーチングを新しいHDRPに対応させる

前回の記事より

気を付けることとして、HDRP6.9.0を使わないと動きません
HDRP、とくに9.x以前はpreviewになっていてバージョン間の互換性がほぼないので、気をつけポイントです

今回は HDRP14.0.8+Unity2022.3.8f1でやりたいので、それに対応させます

  • HDRP6.9.0のLit Shader
  • HDRP14.0.8のLit Shader

のDiffを見ながら、書き換えるべき箇所を一つづつ書き換えていきました

  • 古い方の"HDRP/Lit":879Line 45997chars 15pass
  • 新しい方の"HDRP/Lit":1303Line 69811chars 21pass

という感じで、結構増えています(これは.shaderだけなので、全部展開するともっと増えていると思われます)

ただ、中身を見てみるとそこまで破壊的な変更はなく大きな変更はDXR系のパスくらいなので、レイトレに対応しないのであればやれそうです

結果的に半日かけて書き換え出来ました Shader欲しい方はDMなど下さればあげます

どういう感じで書き換えたかはこちらの殴り書きをご覧ください

hackmd.io

RenderingDebuggerが有用でした

Kanetaさんのレイマーチングシェーダーが無ければこれは無理でした ありがとうございます

平面のシェーダーをPBRの力で良く見せる

今回顕微鏡で見る対象はyonatanさんのこれを考えていました

これをそのまま出すと内臓のぬるっとした感じが出ないので、PBRの力を借ります

HDRPでShaderをコードで書くのは苦行ですので、ShaderGraphを使います
コードが必要な個所はCustomFunctionNodeを使えばいいので簡単です

今回はyonatanさんのシェーダーをベースに内臓をRenderTextureに書き、ShaderGraph側でHeightToNormal Nodeを使ったり、ClearCoatやDepthOffsetをやるとぬるっとしました

これで完成なのですが、謎のエラーが出ました

Shader error in ‘Shader Graphs/ShareNakami_Organ’: Opcode DerivCoarseX not valid in shader model lib_6_3(closesthit). at ShareNakami_Organ(15738) (on d3d11)

これはHDRPでRayTrace OnにしてるとDDX/DDXらへんが使えないので発生します なんかEditor上だと無視しても普通に見えたのでやったーと思っていたのですが、ビルドできませんでした
(公式の人も無理だと言ってる)

最悪なことにRayTraceをOffにしても何故かエラーが止まず、泣く泣くNormal取るのはあきらめました はあ

有用なライブラリなど

特にMinisとInput Systemの組み合わせはマッピングをすっきり書けてかなり良かったです

今回はコントローラーとMidiを併用したので、そこらへんもいい感じに書けるのが良いでした

マッピング/入力について

コントローラーは当初「顕微鏡動かすならスティックだよな~」程度に考えていたのですが、コントローラーは拍を全部押して取る私のVJスタイル(?)にとても合いました

とても押しやすく疲れにくく、タイミングも合いやすかったです

マッピングはこんな感じでした

mapping

コントローラーはこれです なんでもいいので安いやつです

F310ゲームパッド - コンソールスタイル - ロジクールゲーミング

感想

今回やる気が出るまで時間がかかり、前日/当日に8割実装したため、本番直前のビルドで不具合が発生しまくりました(5分前くらいまでビルドしてました)
結局Cookie入れたAreaLightが無いことにされていたのはなぜだったんだ まあできたのでOKです

後AfterParty用に朝日をMidiで操作して昇らせるシーンがあったのですが、AfterPartyが消滅したので深淵に葬られました

VJ ゆるWriteup (VRChat ECHO 2023-10-28)

VJ ゆるWriteup (VRChat ECHO 2023-10-28)

要約

  • UnityHDRP+レイマーチングでジェネVJシステムを作ったよ

はじめに

VRChatのクラブイベント「ECHO」でVJをしました

動機

  • Sh4derJockey(GLSL)だけでVJするのは楽しいが、ずっとやってると表現が凝り固まってしまう気がしたので
  • 楽したい 正規直交基底を書かなくても絵を出したい
  • モダンなリアルタイムレンダリングを触ってみたい

コンセプト

アバターと生と死的な感じ

イメージ/やりたいこと

  • ré3ちゃんを踊らせたい

r3isen.booth.pm

  • CUEで0b4k3さんが荒ぶるやつ

4つ打ちに合わせて確率で荒ぶる

  • 人型モデルが歩く、VJでよく見るやつ

歩く

Milkinsideabagofmilkinsideabagofmilk

もじ

  • 適当なレイマーチングをいれる

いざ実装

HDRPでレイマーチングをやる

Kaneta先生の記事に全部書いてあります

気を付けることとして、HDRP6.9.0を使わないと動きません HDRP、とくに9.x以前はpreviewになっていてバージョン間の互換性がほぼないので、気をつけポイントです 対応するエディタのバージョンもあるので、これを見ます https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@14.0/manual/System-Requirements.html

今回はUnity2019.2.0f1を使います

映像をOBSに送る

https://github.com/keijiro/KlakSpout/tree/v1

v1じゃないと動きません 2019なので

Midi入力を受けとる

https://github.com/keijiro/MidiJack

Minisは動きません 2019なので

文字のシェーダーを書く

"TextMeshPro/Mobile/Distance Field"のシェーダーを改造します

やることは単純で、ノイズでuvを歪めた文字を三回重ねただけです

感想(光)

  • いつもより労力が少ない
    • BRDFを書かなくても絵が出る
  • 文字を自由に出せて楽しい
  • カメラワークが簡単
  • CPUが自由に使える
  • 意外と軽い
  • デバッグがしやすい

感想(闇)

  • GUIをポチる時間があまり楽しくない
    • やっぱり作ってて楽しいのは板ポリGLSL
  • HLSLが嫌い
  • 結局最後の1日でSDF作ることになって、あんまり凝ったものが出せなかった
  • ドラムパッドが押しにくすぎる
    • Midiファイターがほしい

Truchet Tilingのやり方

Truchet Tilingのやり方

要約

・↑これ、Truchet Tilingって言うらしい

・セルを構成する辺の中点に固有のハッシュ値を割り当てることで線の接続/切断を表すとうまくいく

・一番下にソースコードも載せておきました

方針

1.uv=fract(n*uv)などでuvをグリッド状にする

2.floor(n*uv)+.5でセルの中央の点を得る

3.中央点から四方向に座標を足して、辺の中点を得る

4.中点の座標をハッシュ関数にかけて、線の接続/切断を決める

(ex:hash12(mid)<.5)

5.1で得たuvと4で得た接続情報を元にセルの中身を描画する

実装

1~3は割愛します

4

vec2 tci(vec2 uv)
{
  return round(uv*2.)*.5;
}
const vec2[4] dir = vec2[4](vec2(1,0),vec2(0,1),vec2(-1,0),vec2(0,-1));
vec2[4] quv;
int co=0;

float th=mix(.2,.8,sin(time)*.5+.5);
for(int i=0;i<4;i++)
{
    vec2 id=tci(cen+dir[i]*.5);
    if(hash12(id)<th)quv[co++]=dir[i];
}

辺の中点idを得る際、隣のセルとハッシュ値を一致させるため、計算誤差が怖いのでtciという関数を作って丸め込んでいます。

また後に使うため、接続すると決めた点を配列quvに入れています。

5

// qn:接続点がn個のセルの描画をする
float q0(vec2 uv)
float q1(vec2 uv,vec2 p0)
float q2(vec2 uv,vec2 p0,vec2 p1)
  vec2 p=uvf*2.-1.;
  if(co==0)c+=q0(p);
  if(co==1)c+=q1(p,quv[0]);
  if(co==2)c+=q2(p,quv[0],quv[1]);
  if(co==3)
  {
    if(hash12(cen+.42)<.5)
      c+=q1(p,quv[0]),c+=q2(p,quv[1],quv[2]);
    else
      c+=q1(p,quv[1]),c+=q2(p,quv[0],quv[2]);
  }
  if(co==4)
  {
    if(hash12(cen)<.5)
      c+=q2(p,quv[0],quv[1]),c+=q2(p,quv[2],quv[3]);
    else
      c+=q2(p,quv[0],quv[2]),c+=q2(p,quv[1],quv[3]);
  }

接続する点の数coで描画の場合分けをします。 また、セルのuvであるuvfを扱いやすい形に変えます(uv*2.-1.)

q0,q1,q2という関数を定義します。これは接続点がn個のセルの描画をする関数です。 今回の場合、接続点3,4つの描画は(q1+q2)と(q2,q2)で代用しました。ここら辺はいい感じの関数を作るといいと思います

気を付けるのはq2以上で、接続点の並びによって曲線/直線で描き分けるなど、描画を変えるといいと思います

結果

ソースコード

https://gist.github.com/Forenard/eb96f682c46aeb3b10cacd6812f29ba0

GLSLでノイズの等高線をきれいに描く

GLSLでノイズの等高線をきれいに描く

要約

  • 普通にやると線が等幅にならない
  • 勾配を取って、その方向の直線上で評価するときれいな等高線が得られる

このような等高線が得られます

愚直にやった場合

まず考えつくのはfract(noise(uv)*5.0)<0.2のような実装ですが、これでは等高線が等幅になりません

実際にやってみると

vec2 p=FC.xy/r;
float l=.2,f=5.;
float n=snoise2D(p*5.)*.5+.5;
float c=float(fract(n*f)<l);
o+=c;

(ここから動かせます)

確かに等幅にならないことが確認できます

これは、ノイズの変化量が一定でないため起こります

改善案

ノイズに対する勾配を取ることを考えます

手順は以下のようにします

  1. uvをx,yそれぞれの方向に少しだけずらしてノイズを取り、勾配を計算する
  2. floor(noise(uv)*5.0)floor(noise(uv+dir*w)*5.0)を比べて、領域が違う場合線を引く (dir:勾配の方向、w:線の太さ)

こんなイメージです

vec2 uv=FC.xy/r;
float w=.005,f=5.;

#define noise(p) snoise2D((p)*5.)
const vec2 e=vec2(1e-4,0);
float n0=noise(uv+e.xy);
float n1=noise(uv-e.xy);
float n2=noise(uv+e.yx);
float n3=noise(uv-e.yx);
vec2 dir=normalize(vec2(n0-n1,n2-n3));
float i0=floor((noise(uv)*.5+.5)*f);
float i1=floor((noise(uv+dir*w)*.5+.5)*f);
float c=float(abs(i0-i1)>.5);

o+=c;

(ここから動かせます)

追記

@phi16さんより https://iquilezles.org/articles/distance/ を使ってはどうかと教えて頂いたのでそちらでも実装してみます

vec2 uv=FC.xy/r;
float w=.01,f=5.;

#define noise(p) snoise2D((p)*5.)
const vec2 e=vec2(1e-4,0);
float n0=noise(uv+e.xy);
float n1=noise(uv-e.xy);
float n2=noise(uv+e.yx);
float n3=noise(uv-e.yx);
vec2 g=vec2(n0-n1,n2-n3)/(2.*e.x);
float i0=fract((noise(uv)*.5+.5)*f);
float c=float(i0/length(g)<w);

o+=c;

(ここから動かせます)

あまり見た目が変わらず、こちらの方が軽いのでこっちでいい気がします ただ6回やってるので場合によっては私の実装の方が綺麗に出るかもしれません(分からず)

また、今回は実装していませんがsmoothstepを使うことでジャギが軽減されます

まとめ

ノイズを6回(iq先生の方法だと5回)評価するので若干重いですが、その分きれいな等高線が得られます

また、副次的に勾配が取れるのでこのような表現も簡単にできます