Ужасный холст GetImageData () / PutImageData () производительность на мобильном телефоне
Я делаю небольшую игру HTML5, и, загружая мои спрайты в начале карты, я делаю некоторую обработку с помощью GetImageData() / looping по всему изображению / PutImageData().
это работает фантастически здорово на моем компьютере, однако, на моих мобильных телефонах это ужасно медленно.
PC: 5-6 ms
iPhone 4: 300-600 ms
Android HTC Desire S: 2500-3000 ms
Я делал некоторые очень простые бенчмаркинг, и оба GetImageData и PutImageData работают очень быстро, что занимает много времени, это цикл через содержание.
Я очевидно ожидайте замедления на телефоне, но 1000x звучит немного чрезмерно, и загрузка занимает около 4 минут на моем HTC, так что это не сработает. Кроме того, все остальное в игре работает на очень разумной скорости (в основном потому, что экран смехотворно меньше, но все же он работает удивительно хорошо для JS на мобильном телефоне)
то, что я делаю в этой обработке, в основном "затемняет" спрайт до определенного уровень. Я просто перебираю все пиксели и умножаю их на значение
Так как это слишком медленно... Есть ли лучший способ сделать то же самое, используя функциональность холста (композитинг, непрозрачность, что угодно), без цикла через все пиксели один за другим?
Примечание: этот слой имеет около 100% прозрачных пикселей и около 100% непрозрачных пикселей. Оба должны оставаться либо 100% непрозрачными, либо 100% прозрачными.
вещи, о которых я думал это не сработает:
1) покраска спрайтов в новый холст, с меньшей непрозрачностью. Это не сработает, потому что мне нужно, чтобы спрайты оставались непрозрачными, просто темнее.
2) Покраска спрайтов и роспись полупрозрачного черного прямоугольника поверх них. Это сделает их темнее, но это также сделает мои прозрачные пиксели больше не прозрачными...
какие идеи?
это код, который я использую, на всякий случай, если вы видите что-то ужасно идиотское в это:
function DarkenCanvas(baseImage, ratio) {
var tmpCanvas = document.createElement("canvas");
tmpCanvas.width = baseImage.width;
tmpCanvas.height = baseImage.height;
var ctx = tmpCanvas.getContext("2d");
ctx.drawImage(baseImage, 0, 0);
var pixelData = ctx.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height);
var length = pixelData.data.length;
for (var i = 0; i < length; i+= 4) {
pixelData.data[i] = pixelData.data[i] * ratio;
pixelData.data[i + 1] = pixelData.data[i + 1] * ratio;
pixelData.data[i + 2] = pixelData.data[i + 2] * ratio;
}
ctx.putImageData(pixelData, 0, 0);
return tmpCanvas
}
EDIT: это пример того, что я пытаюсь сделать с изображением:
Оригинал: http://www.crystalgears.com/isoengine/sprites-ground.png
Потемнело:http://www.crystalgears.com/isoengine/sprites-ground_darkened.png
спасибо!
Даниэль!--3-->
2 ответов
Phrogz имеет право идея. Вы действительно просто хотите нарисовать полупрозрачный (или прозрачный) черный цвет над всем этим с помощью globalCompositeOperation "source-atop".
вот так:http://jsfiddle.net/F4cNg/
на самом деле был хороший вопрос о сложном затемнении, как это, но автор удалил его, что является настоящим позором. Конечно, можно сделать темные маски на нарисованном материале, даже со сложными формами. Они могут не помочь вы, но ради полноты и для тех, кто ищет" затемненный холст", где некоторые части хранятся в свете (зоны исключения), что можно сделать с помощью " xor " globalCompositeOperation, например:
вы видели этот совет производительности?: http://ajaxian.com/archives/canvas-image-data-optimization-tip
они говорят о сокращении вызовов DOM для повышения производительности.
Итак, основываясь на этом наконечнике, вы можете попробовать:
var pixel = ctx.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height);
pixelData=pixel.data; // detach the pixel array from DOM
var length = pixelData.length;
for (var i = 0; i < length; i+= 4) {
pixelData[i] = pixelData[i] * ratio;
pixelData[i + 1] = pixelData[i + 1] * ratio;
pixelData[i + 2] = pixelData[i + 2] * ratio;
}
ваш .вызовы данных могут замедлить вас.