バンドの練習風景撮ったのを webgl(three.js)で GPGPU 使いつつ curlnoise の particle で遊んでみました。

06/11/2020

仕事だったり育児でなかなか集まれず、
どこか目指してる訳でもないですが続けていきたいなーと思ってるバンドの練習風景撮ったのをwebgl(three.js)で GPGPU とか使いつつ curlnoise で遊んでみました。

ちょっと時間に余裕があった時に気まぐれに始めたらなかなか時間がかかってしまった

成果物等

URL

https://nocebo.jp/band/prs/public/

YOUTUBE


codesandboxで公開しようと思ったけど、
エラー出まくりで一旦諦め中。

ざっくり概要

ざっくり概要としては

  • 複数 video からランダムでビデオテクスチャ切り替え
  • 画角もランダムに切り取ってビデオ描画(背景ビデオ)
  • その上にビデオテクスチャから色参照したパーティクル(カールノイズ)も描画
  • 切り替えや動きはなんとなく音に合わせたタイミング

という感じです。
そこそこ時間かかったので自分で忘れない用に実装内容ある程度記事にしてみます。

ざっくり環境

React

React 歴浅いので多分だめな所いっぱいあります。

react-three-fiber

ReactThree 使うならコレがいいっよて情報みかけたので使ってます。
Three とか GLSL も趣味で触るぐらい。

Typescript

Typescript でやってますが、
個人的には Typescript 嫌い、linter もちょっと頑張ろうかなーって一瞬思ったけど、
ものの数分であきらめました。
遠慮なく any 使って、自分勝手に動けばいいやという感じなのであしからずです。

ソース

準備中

あとは自分用メモがてら詳細というか補足書いていきます。

data

ここで毎フレーム色々アップデートする数値とかまとめてます。
あとそれの確認用の数値とかの表示もReactstate とかで管理すると無駄に再レンダリングはしっちゃう?と思うので
(なんかそれっぽい hook とかあるかもですが)
素で export したのを各所で参照するような作りです。

gl

ここが threecanvas 周りです。

compute

GPGPU 的な処理はここにまとめてます。
three 側の変化はほぼここでつけて他の箇所からはこの compute 参照するだけ。
ereact three fiber だとuseFrame で毎フレームの処理できる様子。

GPUComputationRenderer

用語的にあってるかすら自信ないけど、GPGPU で色々計算すると早い、はず。GPUComputationRenderer っていうの使うと割と手軽にできました。

ライブラリ無しでやると
レンダーバッファのフリップとかが必要だったような?
覚えがあるようなないような。

コメントにも書いてるけど、npm で入れるとなんかエラーが出たので別途手動で配置してます。多分バージョンとかの問題だとは思うけども、

audio の波形なんかも GPU でなんか色々できるらしい。
今後なんかやってみようかな。

shader

glsl もあんまり自信ない部分が多いけども
一応なんとなくコメントは入れてる。

■snoise.glsl

カールノイズと Simplex noise一緒に書いてる。

発散とか内積とか回転とか色々よくはわかってないけど

https://al-ro.github.io/projects/curl/

何となくこのあたり参考にはしました。

■position.fs/velocity.fs

パーティクルの動き周りでいうとここがメインです。
position の位置からカールノイズで速度を取得、
velocity に反映->position に反映。の繰り返し。

今気づいたけど、position の 16:9 はZ 軸考慮しないといけない?かも
けどパッと見は個人的に気にならないので良しとする

■color.fs/mono.fs

ビデオテクスチャ切り取りつつ
色情報とったりってのはここでやってます。
mono.fs はモノクロ処理したやつ

■rgb.fs

rgb シフトほぼ拾ってきただけのやつ、
EffectComposer でやってもいいような処理かもですが
なんとなくパーティクルと背景ビデオで分けたかったのでここに配置

■color_temp.fs/postion_temp.fs

ここは位置とか色情報一旦保持して参照切り替えて
一瞬停止したっぽい演出したくてやってみました。

effect

EffectComposer はココ
Typescript + react-three-fiber だと
IntrinsicElements の interface 定義がないと
駄目っぽい、めんどくさい。

なんで Typescript 普及してるのか謎。
っていいつつ流れには逆らえないので頑張って使う。

particles

パーティクルの vertices とか座標とか、
初期処理がほとんどで前述だけど更新はほとんど compute 側でやってる

shader

■point_position.fs

位置は compute 側参照してるだけ、
あと色情報 varying してる。

■point_vertex.vs

色情報こっちでも取れそうな物な気がしたのだけども知識不足か、
うまくいかなかったので varying で送られた色を mix で切り替えてます。

scene

ここは背景(ベースとなる画角のビデオテクスチャ)のplaneBufferGeometry

media

video とか WebAudio、ストリーミングあと
youtube 用として連番の書き出しとか作ってみました。

audio

時間領域とか周波数領域のグラフ描画だけ、
前述だけどFFTでなんかしようかなと思ってものの
あまり同期できなさそうな気がしたので
パーティクルとかの動作は連動はしてない

あとあんまり自信ないけど、ピークメーターも作ってみた。

recorder

webglの動画ファイルの書き出し

YOUTUBE にもアップしよう思ったのですが
webgl ってどうやってファイルとして書き出せばいいのか分からず
ここが実は結構苦戦した。

調べたら MediaRecorder なるものがあったので、コレだな、
と思って実装してみたけど、どうにもコマ落ちだったりが起こってしまい微妙な気がした。
単に PC のスペックだったり、設定が悪いだけかもしれないけど、

一コマづつjpgで書き出し->ffmpeg

なので代替方法として three 側を await で1フレームづつ
コマ送りしつつ canvasbsae64POST。
phpjpg に書き出し。といゆう手段をとってみた。
その後手動で ffmpeg で連結

で一応割と満足行く画質で書き出し?できた。
youtube にアップしたら自動圧縮で荒れましたが、
まぁ作ってる側だから気になる程度だと思う。

streamLoader

動画のサーバー配信?を何となくやってみたくて
やってみたらここも地味に苦戦した。
分割配信みたいなのもやらないとなーと思ってたんだけど、
webm にしたらそこまで気になる速度じゃないかなとも思ったので
一括で返してます。
webm すごい、変換クソ時間かかるけど

video

ここは video の配置
サーバーから受け取った Bufferblob に変換して src に設定してる。
で合ってると思う。

ui

ここはおまけ、なんかドラッグとかフルスクリーンとかつけてみた。

その他準備中です。