在JavaScript中渲染灯光的速度很慢。任何的想法?

时间:2015-03-15 12:03:34

标签: javascript canvas rendering frame-rate light

我有一个用JavaScript编写的灯光渲染方法,它可以设置每个对象的亮度。如果我在主循环中使用此过滤器调用渲染对象,它将非常慢(8-10 fps)。这对JavaScript来说太过分了,还是只是一个未经优化的解决方案?

如果我在主循环之外调用它,那么它就可以了。

这是Animator类,它有我写的那个方法。您应该使用renderImage开关调用brightness方法。

Animator: { // Animator class 
  renderImage: function(ImageObject,imageX,imageY,filterData = []) {
  /*
    filterData [] =
    0 -> type
    1 -> value for filtering
  */
  switch( filterData[0] )
  {
    case 'none':
      engComponents.ctx.drawImage(ImageObject,imageX,imageY);
      break;

    case 'brightness':
      engComponents.ctx.drawImage(ImageObject,imageX,imageY);
      pixels = engComponents.ctx.getImageData(imageX,imageY,imageX+50,imageY+50);
      data = pixels.data;
      for (var i=0; i<data.length; i+=4) {
        data[i] += filterData[1];
        data[i+1] += filterData[1];
        data[i+2] += filterData[1];
      }
      engComponents.ctx.putImageData(pixels,imageX,imageY);
      break;
  }

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

get / putImageData是相当慢的操作。如果您还需要为每个对象执行此操作,那么期望实时性能更新可能有点太多了。它完全可以用于编译代码和直接访问显卡,但是使用JavaScript和画布,包括它附带的所有故障保险箱,我们不得不陷入诡计。

你可以(可能应该)做的一件事是在游戏开始之前缓存相关图像/对象的变体。定义一些关键亮度值并生成那些精灵表。然后使用亮度而不是实际亮度的索引,这样您只需将具有预期亮度的单元格绘制到屏幕上,而不是在每个帧中进行计算。

让我们以此人为例:

Imgur

现在生成一个具有各种亮度值的精灵表 - 在Photoshop中执行此操作或在代码中动态执行(后面显示在下面的演示中):

sprite

&#13;
&#13;
var sctx = document.getElementById("sprite").getContext("2d"),
    ctx = document.getElementById("main").getContext("2d"),
    img = new Image;
    
img.crossOrigin = "";
img.onload = genSprite;
img.src = "http://i.imgur.com/RV2a28T.png";  // 106x120

function genSprite() {

  sctx.canvas.width = 5 * this.width;          // set sprite size: image width x cells
  sctx.canvas.height = this.width;
  sctx.drawImage(this, 0, 0);                  // draw in image to brighten
  
  
  // generate some brightness cells
  var bStep = 25,                              // brightness step per cell
      max = 5,                                 // max sprites
      idata = sctx.getImageData(0, 0, this.width, this.height), // get once only
      data = idata.data,                       
      len = data.length;
  
  for(var i = 0; i < max; i++) {               // iterate to increase values
    for(var p = 0; p < len; p++) {
      data[p++] += bStep;
      data[p++] += bStep;
      data[p++] += bStep;
    }
    sctx.putImageData(idata, this.width * i, 0); // update at cell pos. with new values
  }
  
  // now we have our sprite-sheet, release the Kraken!
  game();
}

/*==========================================================
This part is just to demonstrate you can draw many instances
with varying brightness without suffer from low frame-rate
==========================================================*/

function game() {

  var dudes = [], // holds Dude objects
      max = 70,   // num. of dudes
      i = 0;
  
  // create game dudes
  while(i++ < max) dudes.push(new Dude(sctx.canvas, ctx));
  
  // animate
  (function loop() {
    ctx.clearRect(0, 0, 500, 500);
    var i = 0;
    while(dude = dudes[i++]) dude.update();  // update dude
    requestAnimationFrame(loop)
  })();
  
}

function Dude(sprite, ctx) {
  var b = (4 * Math.random())|0,   // brightness index (fractional is ok)
      db = 0.25,                   // step for brightness, we round it to integer later
      w = ctx.canvas.width,        // cache some values
      h = ctx.canvas.height,
      x = w * 0.5,                 // center of canvas
      y = h * 0.5,
      v = 1 + 4 * Math.random(),   // random velocity
      a = Math.PI*2*Math.random(), // random angle
      dx = Math.cos(a) * v,        // steps based on angle
      dy = Math.sin(a) * v;
  
  // updates position and brightness cell
  this.update = function() {
    
    // position:
    x += dx;
    y += dy;
    if (x < -106 || x > w || y < -120 || y > h) {
      x = w * 0.5;
      y = h * 0.5;
    }
    
    // brightness:
    b += db;
    if (b <= 0 || b >= 4) db = -db;

    // clip the cell from sprite-sheet and draw to main canvas
    // Note the 106*(b|0) - (b|0) will force integer number which we need.
    ctx.drawImage(sprite, 106*(b|0), 0, 102, sprite.height,  x, y, 106, sprite.height);
  };
}
&#13;
#sprite {border:1px solid #000;margin-bottom:4px;}
&#13;
<canvas id="sprite"></canvas><br>
<canvas id="main" width=500 height=500></canvas>
&#13;
&#13;
&#13;