I am trying to write a program that does some fundamental simulations of particle gravity physics. I originally wrote the program using standard Javascript graphics (with a 2d context), and I could get about 25 fps with 10,000 particles this way. I rewrote the tool in WebGL because I was on the assumption that I could achieve better results this way. I also use the glMatrix library for vector math. However, with this implementation, I only get about 15 frames per second with 10,000 particles.
I am currently an EECS student, and I had a reasonable amount of programming experience, but never with graphics, and I know little how to optimize Javascript code. I don't really understand how WebGL and Javascript work. What key components affect performance when using these technologies? Is there a more efficient data structure to control my particles (I just use a simple array)? What explanation can be made to reduce performance using WebGL? Perhaps delays between the GPU and Javascript?
Any suggestions, explanations or assistance in general are welcome.
I will try to include only the main areas of my code for reference.
Here is my installation code:
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 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);
Drawing cycle:
function drawFrame(){
Here is the class that Square inherits from:
function PhysicsObject(startX,startY,size,mass){ 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 ); vec2.sub(dirVec,GRAV_VEC,this.posVec) vec2.normalize(dirVec,dirVec) vec2.multiply(this.accelVec,this.accelVec,dirVec);
These are the shaders that I use:
<script id="shader-fs" type="x-shader/x-fragment"> void main(void) { gl_FragColor = vec4(0.7, 0.8, 1.0, 1.0); } </script> <script id="shader-vs" type="x-shader/x-vertex"> attribute vec2 a_position; uniform vec2 u_resolution; uniform vec2 u_translation; void main() { </script>
I apologize for being lanky. Again, any suggestions or pushings in the right direction would be huge.