Processingで波動のシミュレーション
Processingで波動のシミュレーションをやってみものの、、、
遅すぎ!
グリッドを100x100くらいにすればまぁなんとかなりますが、
200x200(上のgif)でおっそいなーと感じ、
600x600だと耐えられないレベル
私のPC、16ギガなんですけど!
シミュレーションといっても、難しい計算してないんですけど!
フレームレート上げても、変わらないんですけど!
これは実用に耐えないと思ったら、 GPU使って高速化できるとの記事があったので、早速試してみた が、遅い。
Processingはシミュレーションが苦手いうわけではなく、
画像の描画のオーバーヘッドが重く、その結果遅くなっているようです。
例えば600x600の合計36万個のデータの演算そのものには、
さほど時間かかりませんでした。
例えば、FPSを60にした場合、draw関数は10秒でほぼ600回実行されました。
が、この演算したデータをpoint関数でキャンバス上に描画する際に、
オーバーヘッドが重くのしかかります。
600x600の場合では、FPSが60でも、10秒で20回しかdraw関数は実行されませんでした。
FPS=2ですよ、2。
なにか高速化する手段はないかと探しましたが、
ここはPixelsの出番です。
Pixelsは名前の通り、画素を取り扱うものです。
簡単に述べると、
loadPixels();//キャンバス全体の各画素データを保存 pixels[y*width+x];//キャンバスのx,y座標の画素データを設定 updatePixel();//pixelデータをキャンバスに描画
といった具合です。
シミュレーション画像を描画する際は、
pixelsを使用するとオーバーヘッドが抑えられて高速に描画できます。
試しにpixelを使用して600x600のグリッドでシミュレーションをしてみると
早い!!
これはお薦め!
ソースコードも、わずか3行加えるだけで済みました。
pixelに関連するのは以下のソースのほんのわずか3行です。
loadPixels();//pixelを使用するために必要。 pixels[Y*width + X] = color(amplitude[X][Y]);//各データをpixelデータにする updatePixels();//pixelデータで画像を表示
600x600でこのスピード感。ありがとうpixels。
ソースは以下
void setup() { size(600, 600); noStroke(); background(0, 0, midValue); frameRate(60); initialiseConditions(); setBoundaryConditions(); nextAmplitude = new float[numX][numY]; loadPixels();//pixelを使用するために必要。 } void draw() { // shader(sd); noStroke(); background(0, 0, midValue); for (int X=1; X<numX-1; X++) { for (int Y=1; Y<numY-1; Y++) { nextAmplitude[X][Y] = 2*amplitude[X][Y]; nextAmplitude[X][Y] -= preAmplitude[X][Y]; nextAmplitude[X][Y] += constValue*(amplitude[X-deltaX][Y] +amplitude[X+deltaX][Y] +amplitude[X][Y-deltaX] +amplitude[X][Y+deltaX] -4*amplitude[X][Y]); } } for (int X=0; X<numX; X++) { for (int Y=0; Y<numY; Y++) { preAmplitude[X][Y] = amplitude[X][Y]; pixels[Y*width + X] = color(amplitude[X][Y]);//各データをpixelデータにする amplitude[X][Y] = nextAmplitude[X][Y]; } } updatePixels();//pixelで表示 //Boundary Conditions setBoundaryConditions(); } //境界条件決める関数 void setBoundaryConditions() { //Boundary Conditions for (int X=0; X<numX; X++) { for (int Y=0; Y<numY; Y++) { amplitude[0][Y] = fixedBound; amplitude[numX-1][Y] = fixedBound; } amplitude[X][0] =fixedBound; amplitude[X][numY-1] = fixedBound; } } //各種パラメーター int cnt = 0; int deltaX = 1; int deltaTime = 1; float speed = 0.3; float constValue = pow(float(deltaTime), 2)*pow(speed, 2)/pow(float(deltaX), 2); float[][] amplitude; float[][] preAmplitude; float[][] nextAmplitude; int numX = 600; int numY = 600; float midValue = 128; float fixedBound = 128; float zeroBound = 128; void initialiseConditions() { //Clear amplitude and preAmplitude. amplitude =new float[numX][numY]; preAmplitude =new float[numX][numY]; for (int X=0; X<numX; X++) { for (int Y=0; Y<numY; Y++) { amplitude[X][Y] = midValue; preAmplitude[X][Y] = midValue; } } //Input Initial value. preAmplitude[300][250] = 20; preAmplitude[300][350] = 20; }