🙆

GPU Particle system メモ [TouchDesigner]

2023/02/26に公開

はじめに

Particle systemはCPUでやるパターンとGLSLなどを使ってGPUを通して計算するパターンの王道2パターンがある。
前に、oFを使ってparticleを出すようなものをやろうとしたときに、CPUでやっていたがある程度のところで重さとの戦いになってしまった。
GPU使った方がかしこそうなので、メモしていく。

色々と楽なので、TouchDesigner環境で試していく。

CPU Particle system

Processing, openFrameworksなどでpaticleをやろうとしたときに最初に見つけられて、わかりやすいやつ。
基本的にはオブジェクト指向のclassを使って一つ一つのparticleの位置を管理しながら、加速度、速度、力みたいなのを愚直に一つずつのparticleに対して計算して位置を推定していく。
書きやすく。分かりやすい。

Reference

第4回: openFrameworks – パーティクルを動かす、静的配列と動的配列

Beyond Interaction[改訂第3版]

Simple Particle System / Examples

GLSL Particle system

仕組み的には結構シンプルで、計算処理が重たい位置計算の部分をGPUが使えるGLSLで行おうというだけ。
つまり、画像を用意して、その色情報のRGBを位置情報XYZとして扱うというだけ。

TouchDesignerではGeometry CompのInstancingを使って描画していく。
要には以下のような感じ、Sphere(任意のオブジェクト)につないだGeometry Compを用意して、画像データ(TOP)から、positionのInstanceにrgbを割り当てるだけ。

GLSL TOPを用意して、今から使うものを
pixel formatを16bit float(RGB)に設定する。
これは位置を計算させるために、8bit intとかだと、計算できないから。

解像度もそれぞれのTOPで必要particle数にして増やす。
例として128x128にした。Xresx1のパターンでも良いと思うが

初期座標等々をConstant TOPなどで用意して、GLSL TOPにInputする。(render slect TOPでglslの結果を出せる。GLSL TOPのofColorBuffersを3とかにしといて、renderSlect TOPでそれぞれ3枚受け付けれるようにしておく。)


x=0, y=0.1, z=0

constantをposition用、
noiseをvelosity用に使う。後段にそれぞれfeedbackを置いて、renderSlectでposition, velocityをfeedbakcのTargetTOPに設定しておく。


position用

とりあえず、以下の感じで打てば、初期セットアップとして出力される。

テクスチャは texture 関数を使って サンプリング と呼ばれるプロセスを踏むことで色情報が取り出せます。サンプリングをするには、テクスチャのオブジェクトと、テクスチャのどの座標の色を取り出すかの情報が必要になり、それがそれぞれ sTD2DInputs[0] と vUV.st で指定されています。

GLSL TOP の1番目に接続されたテクスチャは sTD2DInputs[0] で取得することができ、2番目だと sTD2DInputs[1]、3番目だと sTD2DInputs[2] といった具合で使用できます。
[引用]http://satoruhiga.com/TDWS2018/day17/

The ‘st’ are the first and second values of the vec4 (its not uvst, but stpq) So vUV.st is the same as vUV.xy or vUV.rg. It’s like jacques says the uv coordinate (pixel coordinate from 0 to 1).
The ‘out’ qualifier is used to tell the shader what kind of output the shader gives. By default this is a vec4 for 1 buffer. When you use a glslTOP and set the render buffer to > 1, you can use something like:
layout (location = 0) out vec4 fragColor;
layout (location = 1) out vec4 outputBuffer2;
[引用]https://forum.derivative.ca/t/glsl-beginner-vuv-st/145654


// Example Pixel Shader

// uniform float exampleUniform;

//outoput
layout (location = 0) out vec3 posOut;
layout (location = 1) out vec3 velOut;
layout (location = 2) out vec3 colorOut;



// out vec4 fragColor;

void main()
{
	//input
	vec3 posTex = texture(sTD2DInputs[0], vUV.st).rgb;
	vec3 velTex = texture(sTD2DInputs[1], vUV.st).rgb;

	vec3 velNew = velTex;
	vec3 posNew = posTex;

	posOut = posNew;
	velOut = velNew;
	colorOut = vec3(vUV.st, 1.0);

	// vec4 color = vec4(1.0);
	// fragColor = TDOutputSwizzle(color);
}

Green channelがyに対応しているため、velocityに例えば、greenなconstant TOP をaddしてあげると、皆浮き上がる。
GLSLの方でg channelに対してやってあげても同じ。

もう後は好きに処理をCPUの時みたいに付け足すだけで大丈夫。
単純に等速直線運動させたければ


// Example Pixel Shader

// uniform float exampleUniform;

//outoput
layout (location = 0) out vec3 posOut;
layout (location = 1) out vec3 velOut;
layout (location = 2) out vec3 colorOut;



// out vec4 fragColor;

void main()
{
	// //input
	vec3 posTex = texture(sTD2DInputs[0], vUV.st).rgb;
	vec3 velTex = texture(sTD2DInputs[1], vUV.st).rgb;

	vec3 velNew = velTex;
	vec3 posNew = posTex + velNew * 0.01;

	posOut = posNew;
	velOut = velNew;
	colorOut = vec3(vUV.st, 1.0);


	// vec4 color = vec4(vUV.st, 0.0,1.0);
	// fragColor = TDOutputSwizzle(color);
}

地面のバウンスと、抵抗を入れたければ、cpuの時と同じ感じで、

bounce

// Example Pixel Shader

// uniform float exampleUniform;

//outoput
layout (location = 0) out vec3 posOut;
layout (location = 1) out vec3 velOut;
layout (location = 2) out vec3 colorOut;



// out vec4 fragColor;

void main()
{
	// //input
	vec3 posTex = texture(sTD2DInputs[0], vUV.st).rgb;
	vec3 velTex = texture(sTD2DInputs[1], vUV.st).rgb;

	float sphere_rad = 0.01;
	vec3 g = vec3(0, -1, 0);

	vec3 velNew = velTex + g * 0.03;
	vec3 posPredict = posTex + velNew * 0.01;

	//bounce
	if(posPredict.y < sphere_rad){
		float friction = 0.7;
		velNew.y = -friction * velTex.y;
		velNew.xz /= 1.2;
	}

	//すべてのvelocity計算が終わった後にpositionの計算
	vec3 posNew = posTex + velNew * 0.01;

	posOut = posNew;
	velOut = velNew;
	colorOut = vec3(vUV.st, 1.0);


	// vec4 color = vec4(vUV.st, 0.0,1.0);
	// fragColor = TDOutputSwizzle(color);
}

Reference

Particle system in Touchdesigner & GLSL
https://youtu.be/gtdvWZzcpr4

TouchDesigner TOP particle system

32bit float (RG)にする。
XYを表すため

pixelが周りのピクセルで演算されてしまうため、Nearest PixelにInput/Viewer Smoothnesを変更する。

Reference

custom particle system in Touchdesigner
https://youtu.be/QtRIImHD9XU

Discussion