I have a light-rendering method written in JavaScript, which can set the brightness of each object. If I call rendering objects with this filter in the main loop, it'll be very slow (8-10 fps). Is it too much for JavaScript, or just an unoptimized solution?
If I call it outside of the main loop then it's OK.
Here is the Animator
class, which has that method I wrote about. You should call the renderImage
method with the brightness
switch.
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;
}
Thank you for any helping!
get/putImageData are fairly slow operations. If you in addition need to do this for each object, then expecting real-time performance update is perhaps a little too much to hope for. It's fully possible to do with compiled code and direct access to a display card, but with JavaScript and canvas including all the fail safes it comes with, we are forced to dwell in trickery.
One thing you could (probably should) do is to cache variants of the images/objects in question before the game starts. Define some key brightness values and generate a sprite-sheet of those. Then use an index for brightness instead of actual brightness, so you simply draw the cell with the intended brightness to screen instead of calculating during each frame.
Lets take this guy for instance:
Now generate a sprite sheet with various brightness values - do this in Photoshop or dynamically in the code (latter shown in demo below):
var sctx = document.getElementById("sprite").getContext("2d"),
ctx = document.getElementById("main").getContext("2d"),
img = new Image;
img.crossOrigin = "";
img.onload = genSprite;
img.src = "https://i.sstatic.net/pHgNx.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);
};
}
#sprite {border:1px solid #000;margin-bottom:4px;}
<canvas id="sprite"></canvas><br>
<canvas id="main" width=500 height=500></canvas>