web上で物理演算して見たくなりました。目標は10000要素ですが、今回は2D物理演算のライブラリの”Matter.js”を使って大量の円を衝突させて、実用に値するかどうか処理時間を計測してみました。
ちなみにMatter.jsを使えばこんなことが簡単にできます。
大量の要素を物理演算させたい
今回はwebで2D物理演算したいということで、”html+javascript”を使ってコードを作成することにしました。
javascriptで2Dの衝突物理演算をする方法は、自分で1からコードを作る方法とそれ専用のライブラリを使用する方法があります。
自分で1から作るのも面白そうですが、少し労力を伴うので、今回はライブラリを使うことにします。
2D物理演算ライブラリを調べるとBox2Dという有名なライブラリがあるようですが、今回はMatter.jsというライブラリを使います。理由は調べると使っている人も多く、使用例や使い方がいろんなサイトに書かれていることや比較的軽いというのを見たからです。
Matter.jsはこちらのサイトの”Code>Download Zip”でダウンロードできます。あとはその中のmatter.jsをhtmlで参照すれば使えました。
さっそく物理演算
できるだけ単純な物理演算ということで、床と壁に囲まれた領域に大量の円を発生させて自由落下させるといった計算を行いたいと思います。
コードは以下のとおりです。こちらのサイトを参考にしました。
1 2 3 4 5 6 7 8 9 |
#html <html lang="Ja"> <head> </head> <body> <script src="download\matter-js-master\build\matter.js"></script>//matter.jsの読み込み <script type="text/javascript" src="test_matter.js"></script> //test_matter.jsの読み込み以下参照 </body> </html> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
#javascript test_matter.js window.onload = function() { var Engine = Matter.Engine, World = Matter.World, Bodies = Matter.Bodies; // Matter.js エンジン作成 var engine = Engine.create(document.body, { render: { //レンダリングの設定 options: { wireframes: false, //ワイヤーフレームモードをoff width: 1000, //canvasのwidth(横幅) height: 480, //canvasのheight(高さ) background: 'rgba(0, 0, 0, 0)' } } }); //isStatic:地面を追加と壁を追加、静的(完全固定) var ground = Bodies.rectangle(500, 480, 1000, 60, { isStatic: true }); var groundA = Bodies.rectangle(0, 500, 60, 1000, { isStatic: true }); var groundB = Bodies.rectangle(1000, 500, 60, 1000, { isStatic: true }); // 円追加 for (var i = 0; i < 1000; i++) { //1000個の要素円を追加 var rnd = parseInt(Math.random() * 10); var x = 100 + (i%80)*10; var y = 0 - (i/80)*10; World.add(engine.world, [Bodies.circle(x, y, 5, { density: 0.001, // 密度: 単位面積あたりの質量 restitution: 0.7, // 弾力性 friction: 0.2, // 本体の摩擦 })]); } World.add(engine.world, [ground,groundA,groundB, { restitution: 0.7, // 弾力性 friction: 0.2, // 本体の摩擦 }]); //以下は処理速度計測用 var i = 0; var timer = 0.0; var start = 0.0; var end = 0.0; //フレーム毎に実行 Matter.Events.on(engine, 'beforeUpdate', function() { //console.time("loop time"); start = performance.now(); i += 1; }); Matter.Events.on(engine, 'afterUpdate', function() { //console.timeEnd("loop time"); end = performance.now(); timer +=end-start console.log(end-start); console.log(i); if(i>1000){ Matter.Events.off(engine) Engine.clear(engine); console.log("平均処理時間:",timer/1000); } }); // エンジン起動 Engine.run(engine); } |
処理速度検証
要素を変化させて計算が1000回実行されるたときの1回あたりの平均処理時間を算出しました。結果がこちら、指数関数的に時間が増加しているので、縦軸横軸ともに対数軸にしています。
PCのスペックにもよるかもしれませんが、500個くらいまではスムーズに動作しました。ゲームを作成することを想定しても60FPSは出てほしいので”800個”くらいが限界でしょうか。ちなみに私のPCはCPUがIntel Corei7-6900Kでメモリ16GBです。
以下に100個、1000個、10000個の様子を載せておきます。皆さんのPCがカクついているわけではありません。
勝手にカラフルになったよ~
これを見ても10000個ではカックカクなことがわかります。特に衝突し始めてからはより遅延が発生しています。これでは10000個での物理演算は夢のまた夢ですね。
まとめ
今回はMatter.jsを使って大量の物理演算を行ってみました。この状況では10000個は夢のまた夢っぽいので1からコードを作成して負荷をへらす等を検討する必要があるかもしれません。
とはいえ、一般的な物理演算ライブラリではそのような計算を早くする処理はもちろん入っていると思われるので、1から作ったとしてどこまで期待できるかはわかりません。あとは、CPUでなくGPUを使う方法などもできなかなーと模索しています。
コメント