Почему время рендеринга на GPU несовместимо? - PullRequest
0 голосов
/ 05 ноября 2018

Я создаю приложение WebGL с использованием ТРИ и замечаю некоторые странные моменты времени на GPU. В данный момент у меня нет кода репро, но я решил задать вопрос, если это известная ошибка браузера или что-то общее и исправимое.

Настройка сцены

  • Сцена с ~ 2 000 000 полигонов, 136 мешами и 568 экземплярами Object3D.
  • Использование THREE.Composer с проходами FXAA и Unreal Bloom.
  • Использование THREE.OrbitControls.
  • Сцена воспроизводится только тогда, когда известно, что что-то изменилось. Например, рисование запланировано, когда пользователь перетаскивает сцену, чтобы переместить камеру с элементами управления или что-то в сцене перемещается. Сцена часто статична, поэтому мы стараемся не делать ненужной визуализации в этих случаях.

Проблема

Проблема возникает, когда сцена была статичной (ненадолго отрисована), а затем пользователь изменяет положение камеры путем перетаскивания. Как только пользователь начинает перетаскивать, частота кадров становится очень изменчивой - может быть, 10-20 кадров в секунду или ниже - в течение нескольких кадров, прежде чем сгладить обратно до значения, близкого к 60. Это происходит последовательно, когда сцену оставляют в покое на несколько секунд, а затем перетаскивают снова. Если мышь перетаскивается последовательно после начального заикания, то частота кадров остается гладкой. Ничто иное не отображается для этих кадров.

Это заикание не происходит, и сцена остается быстрой, если она визуализируется каждый кадр с использованием requestAnimationFrame.

Вот профилировщик производительности с заиканием, когда сцена воспроизводится только тогда, когда что-то меняется. Вы можете видеть, что на GPU затрачивается гораздо больше времени во время заикания кадров перед повторным сглаживанием:

enter image description here

И профилировщик при рендеринге сцены со скоростью 60 кадров в секунду:

enter image description here

Есть мысли? Почему так много работы с GPU происходит внезапно при перетаскивании? Может ли ничья быть заблокирована каким-то другим процессом рендеринга? Почему это происходит так последовательно после нескольких секунд не рендеринга? Я профилировал, используя последнюю версию Chrome, но заикание присутствует и в Firefox.

Спасибо!

1 Ответ

0 голосов
/ 07 ноября 2018

без живого образца нет простого способа узнать НО ....

1 Three.js может выполнять выборку усеченного конуса на объектах.

Это означает, что если некоторые объекты находятся вне поля зрения, они не будут прорисованы. Итак, установите камеру таким образом, чтобы все объекты были видны, она будет работать медленнее, чем если бы были видны только некоторые объекты

2 Примитивная отсечение

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

3 Depth (Z) Отклонение буфера

Аналогично тому, как описано выше, если ваши объекты непрозрачны, то если пиксель находится за существующим пикселем с помощью теста глубины, графический процессор пропустит вызов пиксельного шейдера, если сможет. Это означает, что если вы рисуете 568 объектов, и первое, что вы рисуете, ближе всего к камере и скрывает много вещей позади нее, то она будет работать быстрее, чем если бы все те вещи, которые позади нее, нарисованы первыми. Three.js имеет возможность сортировки перед рисованием. Обычно сортировка включена для прозрачности, так как прозрачные объекты нужно рисовать задом наперед. Для непрозрачных объектов, хотя рисование спереди назад будет быстрее, если какие-либо передние объекты закроют объекты дальше назад.

4 Рисуете слишком много кадров?

Другой вопрос: как вы ставите в очередь свои дро? в идеале вы ставите в очередь только один розыгрыш, и пока рисунок не состоялся, больше не стоит в очереди.

So

// bad
someElement.addEventListener('mousemove', render);

Приведенный выше код будет пытаться визуализировать при каждом движении мыши, даже если это> 60 кадров в секунду

// bad
someElement.addEventListener('mousemove', () => {
  requestAnimationFrame(render);
});

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

// good?
let frameQueued = false;

function requestFrame() {
  if (!frameQueued) {
    frameQueued = true;
    requestAnimationFrame(render);
  }
}

function render(time) {
  frameQueued = false;
  ...
}      


someElement.addEventListener('mousemove', () => {
  requestFrame();
});

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

...