在 JavaScript 中渲染灯光太慢了。任何想法?
Rendering lights in JavaScript so slow. Any idea?
我有一个JavaScript写的光渲染方法,可以设置每个物体的亮度。如果我在主循环中使用此过滤器调用渲染对象,它将非常慢(8-10 fps)。 JavaScript 是不是太多了,或者只是一个未优化的解决方案?
如果我在主循环之外调用它就没问题。
这里是 Animator
class,其中有我写的那个方法。您应该使用 brightness
开关调用 renderImage
方法。
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;
}
感谢您的帮助!
get/putImageData 是相当慢的操作。如果您还需要为每个对象执行此操作,那么期望实时性能更新可能有点过分。完全可以使用编译代码和直接访问显示卡,但是 JavaScript 和 canvas 包括它附带的所有故障保险,我们被迫陷入诡计。
您可以(可能应该)做的一件事是在游戏开始前缓存相关 images/objects 的变体。定义一些关键的亮度值并生成它们的 sprite-sheet。然后使用亮度索引而不是实际亮度,因此您只需将具有预期亮度的单元格绘制到屏幕上,而不是在每一帧期间进行计算。
让我们以这个人为例:
现在生成具有各种亮度值的精灵 sheet - 在 Photoshop 中或在代码中动态执行此操作(后者在下面的演示中显示):
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);
};
}
#sprite {border:1px solid #000;margin-bottom:4px;}
<canvas id="sprite"></canvas><br>
<canvas id="main" width=500 height=500></canvas>
我有一个JavaScript写的光渲染方法,可以设置每个物体的亮度。如果我在主循环中使用此过滤器调用渲染对象,它将非常慢(8-10 fps)。 JavaScript 是不是太多了,或者只是一个未优化的解决方案?
如果我在主循环之外调用它就没问题。
这里是 Animator
class,其中有我写的那个方法。您应该使用 brightness
开关调用 renderImage
方法。
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;
}
感谢您的帮助!
get/putImageData 是相当慢的操作。如果您还需要为每个对象执行此操作,那么期望实时性能更新可能有点过分。完全可以使用编译代码和直接访问显示卡,但是 JavaScript 和 canvas 包括它附带的所有故障保险,我们被迫陷入诡计。
您可以(可能应该)做的一件事是在游戏开始前缓存相关 images/objects 的变体。定义一些关键的亮度值并生成它们的 sprite-sheet。然后使用亮度索引而不是实际亮度,因此您只需将具有预期亮度的单元格绘制到屏幕上,而不是在每一帧期间进行计算。
让我们以这个人为例:
现在生成具有各种亮度值的精灵 sheet - 在 Photoshop 中或在代码中动态执行此操作(后者在下面的演示中显示):
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);
};
}
#sprite {border:1px solid #000;margin-bottom:4px;}
<canvas id="sprite"></canvas><br>
<canvas id="main" width=500 height=500></canvas>