Как я могу улучшить производительность для нескольких изображений, нарисованных в webgl? - PullRequest
0 голосов
/ 21 мая 2019

Я программирую простое приложение webgl, которое рисует несколько изображений (текстур) друг над другом.В зависимости от положения прокрутки масштаб и непрозрачность изображений изменяются для создания трехмерного многослойного эффекта параллакса.Вы можете увидеть эффект здесь: http://gsstest.gluecksschmiede.io/ct2/

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

Я пробовал / в настоящее время:

  • всегда работаю с одной и той же программой и парой шейдеров
  • изображениянаходятся в 2000x1067 и уже сжаты.Мне нужен PNG из-за прозрачности.Я мог бы сжать их немного больше, но не сильно.Разрешение должно быть таким.
  • уже использует requestAnimationFrame и неблокирующих слушателей прокрутки

Функции webgl, которые я использую для рисования изображения, можно прочитать в этом файле: http://gsstest.gluecksschmiede.io/ct2/js/setup.js

Код шейдера можно найти здесь (просто щелкните правой кнопкой мыши -> показать исходный код): http://gsstest.gluecksschmiede.io/ct2/

По сути, я использовал этот учебник / код и сделал всего несколько изменений:https://webglfundamentals.org/webgl/lessons/webgl-2d-drawimage.html

Затем я использую этот код настройки для рисования изображений в зависимости от текущей позиции прокрутки, как показано в этом файле (см. Метод «update»): http://gsstest.gluecksschmiede.io/ct2/js/para.js

InВ моем приложении около 15 изображений размером 2000x1067 нарисованы друг на друге для каждого кадра.Я ожидал, что это будет работать лучше, чем на самом деле.Я не знаю, что вызывает узкое место.Как вы можете мне помочь:

  • Предоставьте подсказки или идеи, какие сжатие кода / изображения / какие изменения могут улучшить производительность рендеринга
  • Предоставьте справку о том, как отладить производительность.Есть ли что-то более умное, чем просто распечатывать время с помощью console.log и performance.now?
  • Предоставить идеи о том, как я мог бы изящно снизить производительность или обеспечить снижение производительности на старых устройствах.

Ответы [ 2 ]

1 голос
/ 22 мая 2019

Это всего лишь предположение, но ...

Рисование 15 полноэкранных изображений будет медленным во многих системах. Это просто слишком много пикселей. Это не размер изображений, это размер, который они нарисованы. Как и на моем MacBook Air разрешение экрана составляет 2560х1600

Вы рисуете 15 изображений. Эти изображения нарисованы на холсте. Этот холст затем рисуется в окне браузера, а окно браузера затем рисуется на рабочем столе. Так что это как минимум 17 розыгрышей или

 2560 * 1600 * 17 = 70meg pixels

Чтобы получить плавную частоту кадров, мы обычно хотим работать со скоростью 60 кадров в секунду. 60 кадров в секунду означает

 60 frames a second * 70 meg pixels = 4.2gig pixels a second.

Мой графический процессор рассчитан на 8 гигабайт пикселей в секунду, поэтому похоже, что здесь мы можем получить 60 кадров в секунду

Давайте сравним с Macbook Air 2015 года с Intel HD Graphics 6000. Его разрешение экрана составляет 1440x900, которое, если вычислить, достигает 1,3 гигабайта пикселей при 60 кадрах в секунду. Его графический процессор рассчитан на 1,2 гигабайта пикселей в секунду, поэтому мы не получим 60 кадров в секунду на Macbook Air 2015 года

Обратите внимание, что, как и все, указанная максимальная скорость заполнения для графического процессора является одной из тех теоретических максимальных вещей, вы, вероятно, никогда не увидите, что она достигнет максимальной скорости из-за других накладных расходов. Другими словами, если вы посмотрите на скорость заполнения GPU, умножьте ее на 85% или еще что-то (просто предположение), чтобы получить скорость заполнения, которую вы, скорее всего, увидите в реальности.

Вы можете легко это проверить, просто сделайте окно браузера меньше. Если вы сделаете окно браузера на 1/4 размера экрана, и оно будет работать плавно, тогда ваша проблема была заполнена (при условии, что вы изменяете размер буфера рисования холста, чтобы он соответствовал размеру экрана). Это связано с тем, что после того, как вы сделаете, рисуется меньше пикселей (на 75% меньше), но все остальные работы остаются прежними (все javascript, webgl и т. Д.)

Если предположить, что ваша проблема заполнена, то что вы можете сделать

  1. Не рисуйте все 15 слоев.

    Если некоторые слои исчезают до 100% прозрачности, не рисуйте эти слои. Если вы можете спроектировать сайт таким образом, чтобы одновременно отображались только 4-7 слоев, вы значительно продвинетесь ниже предела заполнения

  2. Не рисовать прозрачные области

    Вы сказали 15 слоев, но некоторые из этих слоев в основном прозрачные. Вы можете разбить их на части, скажем, на 9+ (например, на рамку), а не нарисовать средний кусок. Будь то 9 штук или 50 штук, это, вероятно, лучше, чем 80% пикселей, которые на 100% прозрачны.

    Многие игровые движки, если вы дадите им изображение, будут автоматически генерировать меш, который использует только части текстуры, которые> 0% непрозрачны. Например я сделал этот кадр в фотошопе

    enter image description here

    Затем, загрузив его в единое целое, вы увидите, что Unity создал сетку, которая покрывает только не 100% прозрачные части

    enter image description here

    Это то, что вы бы делали в автономном режиме, либо написав инструмент, либо вручную, либо используя какой-либо 3D-редактор сетки, например, Blender, для создания сеток, которые соответствуют вашим изображениям, так что вы не тратите время на рендеринг пикселей с 100 % прозрачный.

  3. Попробуйте отбросить прозрачные пиксели

    Это вам нужно проверить. В ваш фрагментный шейдер вы можете поместить что-то вроде

    if (color.a <= alphaThreshold) {
      discard;  // don't draw this pixel
    }
    

    Где alphaThreashold равно 0,0 или больше. Экономит ли это время, может зависеть от графического процессора, поскольку использование отбрасывания выполняется медленнее, чем нет. Причина в том, что если вы не используете discard, тогда графический процессор может выполнить определенные проверки заранее. В вашем случае, хотя я думаю, что это может быть победой. Обратите внимание, что опция № 2 выше, использование сетки для каждой плоскости, которая покрывает только непрозрачные части, намного лучше, чем эта опция.

  4. Передача большего количества текстур в один шейдер

    Это слишком сложно, но вы могли бы сделать функцию drawMultiImages, которая принимает несколько текстур и несколько матриц текстур и рисует N текстур одновременно. У них всех будет один и тот же прямоугольник назначения, но, отрегулировав исходный прямоугольник для каждой текстуры, вы получите тот же эффект.

    N, вероятно, будет 8 или меньше, поскольку существует ограничение на количество текстур, которое вы можете сделать за один вызов отрисовки, в зависимости от графического процессора. 8 - это минимальное ограничение IIRC, означающее, что некоторые графические процессоры будут поддерживать более 8, но если вы хотите, чтобы все работало везде, вам нужно справиться с минимальным случаем.

    Графические процессоры, как и большинство процессоров, могут читать быстрее, чем могут писать, поэтому чтение нескольких текстур и их смешивание в шейдере будет быстрее, чем выполнение каждой текстуры по отдельности.

  5. Наконец, неясно, почему вы используете WebGL для этого примера.

    Вариант 4 будет самым быстрым, но я бы не рекомендовал его. Мне кажется, слишком много работы для такого простого эффекта. Тем не менее, я просто хочу отметить, что, по крайней мере, на первый взгляд вы можете просто использовать N <div> s и установить их css transform и opacity и получить тот же эффект. У вас остались бы те же проблемы, 15 полноэкранных слоев - это слишком много, и вы должны скрыть <div> s, у которых непрозрачность равна 0% (браузер может сделать это для вас, но лучше не принимать в расчет). Вы также можете использовать 2D Canvas API, и вы должны увидеть аналогичные перфокарты. Конечно, если вы делаете какой-то особый эффект (не смотрел на код), тогда не стесняйтесь использовать WebGL, на первый взгляд, это было неясно.

1 голос
/ 21 мая 2019

Пара вещей:

Профилирование производительности показывает, что ваша проблема не в webgl, а утечка памяти .

Сжатие изображений не имеет смысла в webgl , так как webgl не заботится о png, jpg или webp.Текстуры всегда представляют собой массивы байтов в графическом процессоре, поэтому каждый из ваших слоев имеет размер 2000 *1067* 4 байта = 8,536 мегабайт.

Никогда не создавайте данные в цикле анимации , вы это делаете,узнайте, как использовать библиотеку математики, которую вы используете.

...