Какой самый быстрый способ рисовать на холсте HTML 5? - PullRequest
13 голосов
/ 19 января 2012

Я исследую возможность создания игры, используя только холст HTML в качестве средства отображения. Чтобы взять пример задания, которое мне нужно сделать, мне нужно построить игровое окружение из множества изометрических плиток. Конечно, работа в 2D означает, что они обязательно должны быть в прямоугольных пакетах, поэтому между плитками существует большое перекрытие.

Я достаточно взрослый, чтобы естественным решением этой проблемы было вызвать BitBltMasked. Ой, нет, нет, HTML-холст не имеет ничего более простого и приятного, чем BitBlt. Кажется, что единственный способ выгрузить пиксельные данные на холст - это либо с помощью drawImage (), у которого нет полезных режимов рисования, которые игнорируют альфа-канал, либо использовать объекты ImageData, у которых есть данные изображения в массиве… для которого каждый. доступ. является. границы. проверено. а также. следовательно. собака. медленно.

Хорошо, это скорее пустяк, чем вопрос (вещи, которые нравятся W3C, как правило, провоцируют это у меня), но что я действительно хочу знать, так это как быстро рисовать на холсте? Мне очень трудно избавиться от ощущения, что выполнение сотен операций drawImages () в секунду, когда каждое рисование учитывает альфа-канал, по сути своей греховно и может заставить мое приложение работать как задница во многих браузерах. С другой стороны, единственный способ правильно реализовать BitBlt в значительной степени опирается на браузер, использующий технику выполнения, похожую на точку доступа, чтобы он работал быстро.

Есть ли способ быстро рисовать во всех возможных реализациях или мне просто нужно забыть о производительности?

Ответы [ 3 ]

3 голосов
/ 12 мая 2014

Это действительно интересная проблема, и есть несколько интересных вещей, которые вы можете сделать, чтобы решить ее.

Во-первых, вы должны знать, что drawImage может принимать Canvas, а не только изображение. «Sub-Canvas» даже не должны быть в DOM. Это означает, что вы можете создать композицию на одном холсте, а затем нарисовать ее на другом. Это открывает целый мир возможностей оптимизации, особенно в контексте изометрических плиток.

Допустим, у вас есть область длиной 50 плиток и шириной 50 плиток (я скажу метры ради моего здравомыслия). Вы можете разделить область на 10x10 м кусков. Каждый кусок представлен своим собственным холстом. Чтобы нарисовать полную сцену, вы просто должны нарисовать каждый из объектов Canvas чанков на главном холсте, который показан пользователю. Если бы только четыре куска (площадь 20x20 м), вы выполняли бы только четыре drawImage операции.

Конечно, каждый из этих отдельных кусков должен будет отображать свой собственный холст. На игровых галочках, когда в чанке ничего не происходит, вы просто ничего не делаете: холст останется неизменным и будет нарисован так, как вы ожидаете. Когда что-то меняется, вы можете сделать одну из нескольких вещей в зависимости от вашей игры:

  1. Если ваши плитки выходят в третье измерение (т. Е. У вас есть ось Z), вы можете нарисовать каждый «слой» фрагмента в его собственном Canvas и обновить только те слои, которые необходимо обновить. Например, если каждый блок содержит десять слоев глубины, у вас будет десять объектов Canvas. Если что-то на 6-м слое было обновлено, вам нужно будет только перекрасить Canvas 6-го слоя (вероятно, одну drawImage на квадратный метр, что будет 100), а затем выполнить одну операцию drawImage на слой в блоке (десять) перерисовать холст чанка. Уменьшение или увеличение размера чанка может увеличить или уменьшить производительность в зависимости от количества обновлений, которые вы вносите в среду в своей игре. Дальнейшая оптимизация может быть сделана для устранения drawImage вызовов для скрытых плиток и тому подобного.
  2. Если у вас нет третьего измерения, вы можете просто выполнить один drawImage на квадратный метр куска. Если обновляются два чанка, то это только 200 drawImage вызовов на тик (плюс один вызов на чанк, видимый на экране). Если ваша игра содержит очень мало обновлений, уменьшение размера чанка приведет к еще большему уменьшению количества вызовов.
  3. Вы можете выполнять обновления чанков в собственном игровом цикле. Если вы используете requestAnimationFrame (как и должно быть), вам нужно рисовать только куски объектов Canvas на экране. Независимо от этого, вы можете выполнять игровую логику в цикле setTimeout и т.п. Затем каждый блок может обновляться в своем собственном тике между кадрами, не влияя на производительность. Это также может быть выполнено веб-работником, использующим getImageData и putImageData для отправки визуализированного чанка обратно в основной поток всякий раз, когда он должен быть обновлен, хотя выполнение этой работы без проблем потребует значительных усилий.

Другой вариант, который у вас есть, - использовать библиотеку, подобную pixi.js, для рендеринга сцены с использованием WebGL. Даже для 2D это повысит производительность, уменьшив объем работы, который требуется ЦП, и перенеся его на графический процессор. Я очень рекомендую проверить это.

1 голос
/ 11 мая 2012

Я знаю, что GameJS имеет операции blit, и я, конечно, предполагаю, что любые другие библиотеки игр html5 также работают (gameQuery, LimeJS и т. Д. И т. Д.).Я не знаю, отвечали ли эти пакеты конкретной проблеме проверки границ массивов, но на практике их образцы работают достаточно быстро на всех платформах.

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

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

У меня нет личных знаний об этом, но вы можете заглянуть в элемент appMobi "direct canvas", который предположительно являетсягораздо более быстрая версия обычного холста, ссылка .Я запутался в том, работает ли это во всех браузерах или только в браузерах webkit, или просто в собственном специальном браузере appMobi.

Опять же, вы не должны делать предположения о том, какие ускорения имеют смысл без очень глубокого знания внутренних процессов веб-браузера.,На этой веб-странице о «прямом холсте» упоминается множество вещей, которые замедляют рисование холста: «Перефразирование текста, сопоставление горячих точек, создание индексов для ссылочных ссылок и т. Д.».Альфа-смешение и проверка границ массивов не упоминаются в качестве основных причин медлительности!

0 голосов
/ 04 августа 2014

К сожалению, нет никакого способа обойти альфа-композицию.Отсечение может быть одним из решений, но я сомневаюсь, что прирост производительности будет очень большим.Не говоря уже о том, как сложен такой маршрут для реализации на неправильных формах.

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

Но, тем не менее, браузеру приходится перерисовывать каждый пиксель в другом месте на холсте.Что довольно дорого.Было бы неплохо, если бы существовал метод только для прокрутки пикселей, но и тут не повезло.

Одна мысль, которая приходит в голову, состоит в том, что вы можете реализовать несколько холстов, переводя каждый отдельный canvas вместо перерисовки пикселей.Это позволило бы браузеру решить, как перерисовать эти пиксели более естественным образом, по крайней мере, теоретически.Затем вы можете визуализировать новые видимые плитки на новом или используемом / кэшированном элементе canvas.Позиционирование так, чтобы оно совпадало с последним рендером экрана.

Но это только мои два блита ... Я имею в виду биты ... да, я имею в виду центы:]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...