title: Efficient way to animate grass in canvas
body: <p>I have been playing around with the capabilities of the 2d context of the canvas element to try to create relatively realistic 3d scenes and am currently trying to create a plain of 3d 'ish' grass as per fiddle:</p>
  
  <p><a href="http://jsfiddle.net/PlacidCow/j6h7sajz/" rel="nofollow">http://jsfiddle.net/PlacidCow/j6h7sajz/</a></p>
  
  <p>My question is, what is the most efficient way to animate the grass to take in the effects of wind/physics etc?</p>
  
  <p>Currently I've just drawn to screen - I have tried storing the dimensions of each blade in a large array which ofc then takes ages to loop through to animate (hence is laggy and pointless). Is there an efficient way to draw per blade? Or would people recommend animating per block (but then how to fix as clearing a patch will mess up blades in front)? repeating blades so they batch animate? </p>
  
  <p>Have looked online (maybe I lack googling skills...) but I either find nothing, cagey webgl demos or examples for C etc but this use shaders which aren't available for 2d canvas.</p>
  
  <pre><code>c = document.getElementsByTagName('canvas')[0];
  ctx = c.getContext('2d');
  
  var v = {
      w: c.clientWidth,
      h: c.clientHeight
  };
  c.width = v.w;
  c.height = v.h;
  
  var base = {
      c: [
          [-1, -1, 0],
          [-1, -1, -1],
          [1, -1, -1],
          [1, -1, 0]
      ],
      f: 'brown',
      d: -3
  };
  
  draw(base.c, base.f, base.d);
  
  for (var j=1; j&lt;120; j++) {
      for (var k=1; k&lt;200; k++) {
          var z = -1 + 2*j/199;
          var x = -1 + (2*Math.random())/1.01;
          var y = 0.06+Math.random()*0.04;
          var fl = Math.pow(-1, (Math.random()*1000)|0) * Math.random()/20;
          var blade = {
  c: [
      [x, -1, z-Math.random()/1000],
      [x+0.002+fl, -1+y, z-Math.random()/1000],
      [x+0.007+fl, -1+y, z-Math.random()/1000],
      [x+0.02, -1, z-Math.random()/1000]
  ],
  f: 'green',
  d: 2
          };
          draw(blade.c, blade.f, blade.d);
      }
  }
  
  function draw(cds, fill, d) {
      var v = {
          w: c.clientWidth,
          h: c.clientHeight
      };
  
      ctx.beginPath();
  
      ctx.moveTo(((cds[0][0] * (1 / (1 - cds[0][2])) + 1) * v.w / 2)|0, ((v.h - (cds[0][1] + 1) * v.h / 2) * (1 / (1 - cds[0][2])))|0);
  
      for (var i = 1; i &lt; cds.length; i++) {
          ctx.lineTo(((cds[i][0] * (1 / (1 - cds[i][2])) + 1) * v.w / 2)|0, ((v.h - (cds[i][1] + 1) * v.h / 2) * (1 / (1 - cds[i][2])))|0);
  }
          ctx.lineTo(((cds[0][0] * (1 / (1 - cds[0][2])) + 1) * v.w / 2)|0, ((v.h - (cds[0][1]+1) * v.h / 2) * (1 / (1 - cds[0][2])))|0);
  
      if (Math.abs(d) == 1) {
          grd = ctx.createLinearGradient((200-200*d/Math.abs(d))/2, 0, (200+200*d/Math.abs(d))/2,0);
      } else if (Math.abs(d) == 2) {
          grd = ctx.createLinearGradient(0,((v.h - (cds[1][1] + 1) * v.h / 2) * (1 / (1 - cds[1][2])))|0,0,((v.h - (cds[0][1] + 1) * v.h / 2) * (1 / (1 - cds[0][2])))|0+v.h/100);
      } else if (Math.abs(d) == 3) {
          grd = ctx.createLinearGradient(0,(200-200*d/Math.abs(d))/2, 0, (200+200*d/Math.abs(d))/2);
      }
      grd.addColorStop(0, fill);
      grd.addColorStop(1, '#000');
  
      ctx.fillStyle = grd;
      ctx.fill();
  }
  </code></pre>