粒子の基本的な重力物理シミュレーションを行うプログラムを作成しようとしています。私は当初、標準の Javascript グラフィック (2D コンテキストを使用) を使用してプログラムを作成しましたが、その方法で 10000 パーティクルで約 25 fps を得ることができました。ツールを WebGL で書き直したのは、その方がより良い結果が得られるという仮定の下にあったためです。ベクトル演算には glMatrix ライブラリも使用しています。ただし、この実装では、10000 個のパーティクルで約 15 fps しか得られません。
私は現在 EECS の学部生で、ある程度のプログラミング経験はありますが、グラフィックスの経験はなく、Javascript コードを最適化する方法についてはほとんど手がかりがありません。WebGL と Javascript がどのように機能するかについて、私には理解できないことがたくさんあります。これらのテクノロジーを使用する場合、どの主要コンポーネントがパフォーマンスに影響しますか? パーティクルを管理するために使用するより効率的なデータ構造はありますか (単純な配列を使用しているだけです)。WebGL を使用した場合のパフォーマンスの低下について、どのような説明が考えられますか? GPU と Javascript の間の遅延でしょうか?
一般的な提案、説明、またはヘルプをいただければ幸いです。
参照用にコードの重要な領域のみを含めるようにします。
ここに私のセットアップコードがあります:
gl = null;
try {
// Try to grab the standard context. If it fails, fallback to experimental.
gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
}
catch(e) {}
if(gl){
gl.clearColor(0.0,0.0,0.0,1.0);
gl.clearDepth(1.0); // Clear everything
gl.enable(gl.DEPTH_TEST); // Enable depth testing
gl.depthFunc(gl.LEQUAL); // Near things obscure far things
// Initialize the shaders; this is where all the lighting for the
// vertices and so forth is established.
initShaders();
// Here's where we call the routine that builds all the objects
// we'll be drawing.
initBuffers();
}else{
alert("WebGL unable to initialize");
}
/* Initialize actors */
for(var i=0;i<NUM_SQS;i++){
sqs.push(new Square(canvas.width*Math.random(),canvas.height*Math.random(),1,1));
}
/* Begin animation loop by referencing the drawFrame() method */
gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
gl.vertexAttribPointer(vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0);
requestAnimationFrame(drawFrame,canvas);
描画ループ:
function drawFrame(){
// Clear the canvas before we start drawing on it.
gl.clear(gl.COLOR_BUFFER_BIT);
//mvTranslate([-0.0,0.0,-6.0]);
for(var i=0;i<NUM_SQS;i++){
sqs[i].accelerate();
/* Translate current buffer (?) */
gl.uniform2fv(translationLocation,sqs[i].posVec);
/* Draw current buffer (?) */;
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
window.requestAnimationFrame(drawFrame, canvas);
}
Square が継承するクラスは次のとおりです。
function PhysicsObject(startX,startY,size,mass){
/* Class instances */
this.posVec = vec2.fromValues(startX,startY);
this.velVec = vec2.fromValues(0.0,0.0);
this.accelVec = vec2.fromValues(0.0,0.0);
this.mass = mass;
this.size = size;
this.accelerate = function(){
var r2 = vec2.sqrDist(GRAV_VEC,this.posVec)+EARTH_RADIUS;
var dirVec = vec2.create();
vec2.set(this.accelVec,
G_CONST_X/r2,
G_CONST_Y/r2
);
/* Make dirVec unit vector in direction of gravitational acceleration */
vec2.sub(dirVec,GRAV_VEC,this.posVec)
vec2.normalize(dirVec,dirVec)
/* Point acceleration vector in direction of dirVec */
vec2.multiply(this.accelVec,this.accelVec,dirVec);//vec2.fromValues(canvas.width*.5-this.posVec[0],canvas.height *.5-this.posVec[1])));
vec2.add(this.velVec,this.velVec,this.accelVec);
vec2.add(this.posVec,this.posVec,this.velVec);
};
}
これらは私が使用しているシェーダーです:
<script id="shader-fs" type="x-shader/x-fragment">
void main(void) {
gl_FragColor = vec4(0.7, 0.8, 1.0, 1.0);
}
</script>
<!-- Vertex shader program -->
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
uniform vec2 u_translation;
void main() {
// Add in the translation.
vec2 position = a_position + u_translation;
// convert the rectangle from pixels to 0.0 to 1.0
vec2 zeroToOne = position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace*vec2(1,-1), 0, 1);
}
</script>
長々と失礼いたしました。繰り返しになりますが、正しい方向への提案や微調整は非常に大きなものになります。