html5 canvas - сохранение путей или областей обрезки для повторного использования

В настоящее время я реализую эффект двумерной деформируемой местности в игре, над которой я работаю, и она идет хорошо, но я могу представить, что она очень быстро превратится в скачок производительности, когда я начну добавлять больше слоев к эффекту.

Теперь я ищу способ сохранить путь, или обтравочную маску или подобное, вместо того, чтобы хранить каждую точку пути на местности, которую мне нужно рисовать через каждый кадр. И так как я добавляю больше слоев, мне придется все больше перебирать путь, который может содержать тысячи точек.

Какой-то очень простой код для демонстрации того, что я сейчас делаю

for (var i = 0; i < aMousePoints.length; i++)
{
    cRenderContext.save();
    cRenderContext.beginPath();
    var cMousePoint = aMousePoints[i];
    cRenderContext.arc(cMousePoint.x, cMousePoint.y, 30, 0, 2 * Math.PI, false);
    cRenderContext.clip();
    cRenderContext.drawImage(cImg, 0, 0);
    cRenderContext.closePath();
    cRenderContext.restore();
}

По сути, мне нужен эффективный способ рисовать мою обтравочную маску для моего изображения снова и снова над каждым кадром.

3 ответа

Решение

Обратите внимание, что ваш регион отсечения остается точно таким же, за исключением его местоположения x/y. Это большой плюс.

Область отсечения - это одна из вещей, которая сохраняется и восстанавливается с context.save() а также context.restore() таким образом, его можно сохранить таким образом (другими словами, определяя его только один раз). Когда вы хотите разместить его, вы будете использовать ctx.translate() вместо дуги х, у.

Но, вероятно, более эффективно сделать это вторым способом:

  1. Имейте холст в памяти (никогда не добавляемый в DOM или показанный на странице), который предназначен исключительно для содержания области отсечения и является размером области отсечения
  2. Примените область отсечения к этому холсту в памяти, а затем нарисуйте изображение на этом холсте.
  3. Тогда используйте drawImage с холстом в памяти на ваш игровой контекст. Другими словами: cRenderContext.drawImage(in-memory-canvas, x, y); где х и у - подходящее место.

Таким образом, область отсечения всегда остается на одном месте и рисуется только один раз. Изображение перемещается на холст отсечения и затем рисуется, чтобы выглядеть правильно, а затем холст в памяти перетягивается на ваш основной холст. Так должно быть намного быстрее, так как drawImage намного быстрее, чем создание и рисование контуров.

В качестве отдельного рассмотрения производительности не называйте save а также restore если только ты не должен. Они занимают время, и они не нужны в вашем цикле выше.

Если ваш код с открытым исходным кодом, дайте мне знать, и, если хотите, я посмотрю на его производительность в целом.

Почему бы не иметь один холст для переднего плана и один холст для фона? Как в следующей демонстрации

Демонстрация переднего плана / фона (возможно, я немного переборщил, делая демо: "Я люблю возиться с JS/canvas.

Но в основном холст переднего плана прозрачен помимо содержимого, поэтому он действует как маска поверх фона холста.

Похоже, что теперь это возможно с новым объектом path2D.

Новый API Path2D (доступен в Firefox 31+) позволяет хранить пути, что упрощает код рисования на холсте и ускоряет его работу. Конструктор предоставляет три способа создания объекта Path2D:

new Path2D();     // empty path object
new Path2D(path); // copy from another path
new Path2D(d);    // path from from SVG path data

Третья версия, которая использует данные пути SVG для создания, особенно удобна. Теперь вы можете повторно использовать пути SVG, чтобы рисовать те же фигуры непосредственно на холсте:

var p = new Path2D("M10 10 h 80 v 80 h -80 Z");

Информация взята с официального сайта Mozilla.

Другие вопросы по тегам