Производительность комплекта сцен с тестом куба
Изучая программирование трехмерной графики для игр, я решил начать с простого, используя Scene Kit 3D API. Моей первой игровой целью было создать очень упрощенную мимику MineCraft. Игра только в кубики - как это может быть сложно.
Ниже приведен цикл, который я написал, чтобы разместить 100 кубов (10000), и производительность FPS была ужасной (~ 20 кадров в секунду). Является ли моя первоначальная игровая цель слишком большой для Scene Kit или есть лучший способ приблизиться к этому?
Я читал другие темы на StackExchange, но не чувствую, что они отвечают на мой вопрос. Преобразование открытых блоков поверхности в одну сетку не будет работать, так как SCNGeometry является неизменным.
func createBoxArray(scene : SCNScene, lengthCount: Int, depthCount: Int) {
let startX : CGFloat = -(CGFloat(lengthCount) * CUBE_SIZE) + (CGFloat(lengthCount) * CUBE_MARGIN) / 2.0
let startY : CGFloat = 0.0
let startZ : CGFloat = -(CGFloat(lengthCount) * CUBE_SIZE) + (CGFloat(lengthCount) * CUBE_MARGIN) / 2.0
var currentZ : CGFloat = startZ
for z in 0 ..< depthCount {
currentZ += CUBE_SIZE + CUBE_MARGIN
var currentX = startX
for x in 0 ..< lengthCount {
currentX += CUBE_SIZE + CUBE_MARGIN
createBox(scene, x: currentX, y: startY, z: currentZ)
}
}
}
func createBox(scene : SCNScene, x: CGFloat, y: CGFloat, z: CGFloat) {
var box = SCNBox(width: CUBE_SIZE, height: CUBE_SIZE, length: CUBE_SIZE, chamferRadius: 0.0)
box.firstMaterial?.diffuse.contents = NSColor.purpleColor()
var boxNode = SCNNode(geometry: box)
boxNode.position = SCNVector3Make(x, y, z)
scene.rootNode.addChildNode(boxNode)
}
ОБНОВЛЕНИЕ 12-30-2014: Я изменил код так, что SCNBoxNode создается один раз, а затем каждый дополнительный блок в массиве 100 x 100 создается с помощью:
var newBoxNode = firstBoxNode.clone()
newBoxNode.position = SCNVector3Make(x, y, z)
Это изменение, похоже, увеличило FPS до ~ 30 кадров в секунду. Другие статистические данные следующие (из статистики, отображаемой в SCNView):
10K (я предполагаю, что это вызовы отрисовки?) 120K (я предполагаю, что это лица) 360K (при условии, что это число вершин)
Большая часть цикла выполнения находится в рендеринге (я предполагаю, 98%). Общее время цикла составляет 26,7 мс (ой). Я работаю на Mac Pro Late 2013 (6-ядерный с Dual D500 GPU).
Учитывая, что игра в стиле MineCraft имеет ландшафт, который постоянно меняется в зависимости от действий игроков, я не понимаю, как я могу оптимизировать это в рамках Scene Kit. Большое разочарование, так как мне очень нравятся рамки. Я хотел бы услышать чьи-то идеи о том, как я могу решить эту проблему - без этого я вынужден пойти с OpenGL.
ОБНОВЛЕНИЕ 12-30-2014 @ 2:00 вечера ET: Я вижу значительное улучшение производительности при использовании flateredClone (). FPS теперь составляет 60 кадров в секунду даже с большим количеством ящиков и ДВУХ вызовов. Однако адаптация динамической среды (как поддерживает MineCraft) по-прежнему проблематична - см. Ниже.
Поскольку массив со временем меняет состав, я добавил обработчик keyDown, чтобы добавить еще больший массив ящиков к существующему, и рассчитал разницу между добавлением массива ящиков, что привело к гораздо большему количеству вызовов по сравнению с добавлением в виде flatlinedClone. Вот что я нашел:
На keyDown я добавляю еще один массив размером 120 x 120 (14 400 ящиков)
// This took .0070333 milliseconds
scene?.rootNode.addChildNode(boxArrayNode)
// This took .02896785 milliseconds
scene?.rootNode.addChildNode(boxArrayNode.flattenedClone())
Повторный вызов flatenedClone () в 4 раза медленнее, чем добавление массива.
Это приводит к двум вызовам рисования, имеющим 293 тыс. Граней и 878 тыс. Вершин. Я все еще играю с этим и буду обновлять, если найду что-нибудь новое. В итоге, с моим дополнительным тестированием я все еще чувствую неизменные геометрические ограничения Scene Kit, означающие, что я не могу использовать каркас.