2016-11-04 8 views
1

У меня проблема с приложением SceneKit (используя Metal), когда новые узлы появляются на экране, даже если приложение работает плавно со скоростью 60 кадров в секунду до и после.Приложение SceneKit заикается, когда появляются новые узлы

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

Что я сделал до сих пор, чтобы попытаться исправить заикание: Я предварительно загружаю узлы с помощью метода предварительной загрузки вида SceneKit и добавляю их в сцену только в своем обработчике завершения. Я добавляю их над камерой задолго до того, как их нужно будет показать, и когда придет время, я просто перевешу их в нужное положение. Я реализовал механизм очередей, чтобы обеспечить только одно изменение (удаление узла уничтоженного элемента, перемещение его на место) выполняется для каждого кадра.

Но заикание по-прежнему происходит иногда (не всегда), когда появляются бонусы. Мне интересно, делает ли SceneKit что-то только тогда, когда узлы появляются впервые (даже если они были предварительно загружены). Что бы ни случилось, кажется, достаточно, чтобы вызвать заикание, но слишком короткое для измерителей производительности XCode, чтобы показать это. В каждом фрейме много свободного времени, процессор и графический процессор никогда не приближаются к максимальному.

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

Любая идея, что здесь происходит или как я могу отслеживать это?

ответ

0

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

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

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

Самый простой способ обойти это - заменить шейдеры SceneKit собственным кодом (используя SCNProgram), но это также избавит вас от большинства удобств, которые предоставляет SceneKit. Так как это не то, что я хотел, у меня был следующий подход:

Я заставляю SceneKit сначала скомпилировать все шейдеры всех узлов, которые могут стать видимыми позже, покрывая сцену черным наложением в начале, добавляя все узлы перед камерой, а затем перемещая их в правильные положения, прежде чем погасить слой покрытия. Я также избегаю перекомпиляции, никогда не полностью отключая эффекты, которые мне не нужны все время (например, свет выключается, изменяя его интенсивность до 0,1 вместо 0). Это приводит к тому, что SceneKit все время сохраняет одинаковые шейдеры и, таким образом, избегает заикания.

Опять же: Apple не подтвердила это, но она работала до сих пор, поэтому я считаю, что мои предположения верны ;-).