Производительность сцены с тестом на куб

Изучая 3D-графическое программирование для игр, я решил начать с простого, используя 3D Scene Kit. Моя первая игровая цель состояла в том, чтобы создать очень упрощенную имитацию MineCraft. Игра просто кубиков - как это сложно.

Ниже приводится цикл, который я написал, чтобы поместить ход 100 х 100 кубов (10 000), а производительность FPS была ужасной (~ 20 FPS). Является ли моя первоначальная игровая цель слишком много для 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 мс (ouch). Я работаю на Mac Pro Late 2013 (6-ядерный/Dual D500 GPU).

Учитывая, что у игры в стиле MineCraft есть пейзаж, который постоянно изменяется на основе действий игроков, я не вижу, как я могу оптимизировать это в рамках набора сцен. Большое разочарование, так как мне очень нравится фреймворк. Мне бы хотелось услышать какие-то идеи о том, как я могу решить эту проблему - без этого я вынужден пойти с OpenGL.

ОБНОВЛЕНИЕ 12-30-2014 @14:00 ET: При использовании flattenedClone() я вижу значительное улучшение производительности. Теперь FPS имеет сплошную 60 кадров в секунду даже с большим количеством ящиков и двумя вызовами рисования. Однако размещение динамической среды (с поддержкой MineCraft) по-прежнему является проблематичным - см. Ниже.

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

В keyDown я добавляю еще один массив из 120 x 120 ящиков (14 400 полей)

// This took .0070333 milliseconds
scene?.rootNode.addChildNode(boxArrayNode)
// This took .02896785 milliseconds
scene?.rootNode.addChildNode(boxArrayNode.flattenedClone())

Вызов flattenedClone() снова на 4 раза медленнее, чем добавление массива.

Это приводит к двум вызовам рисования, имеющим 293K граней и 878K вершин. Я все еще играю с этим и буду обновляться, если найду что-нибудь новое. В нижней строке, с моим дополнительным тестированием, я все еще чувствую, что набор неподвижных геометрических ограничений Scene Kit означает, что я не могу использовать фреймворк.

Ответ 1

Как вы упомянули Minecraft, я думаю, стоит посмотреть, как это работает.

У меня нет технических деталей или кода для вас, но все должно быть довольно откровенно:

Вы когда-нибудь играли в minecraft онлайн, а местность не загружалась, позволяя вам видеть? Это потому, что внутри нет геометрии.

предположим, что у меня есть массив 2x2x2 кубов. Это делает 2 * 2 * 2 * 6 * 2 = 96 треугольников.

Однако, если вы проверяете и рисуете только полигоны на видимом с точки зрения камеры, возможно, тестируя нормали (легко, так как это кубики), это число уменьшается до 48 треугольников.

Если вы обнаружите способ увидеть, какие лица закрыты другими (что не должно быть слишком сложным, если вы считаете, что работаете с плоскими, квадратными гранями), вы можете их только рисовать. Таким образом, мы рисуем от 8 до 24 треугольников. Это до 90% оптимизации.

Если вы хотите получить действительно глубокое, вы можете даже комбинировать лица, чтобы сделать один N-угольник из видимых плоских лиц. Вы можете сделать это, если вы создадите новый способ генерации геометрии "на лету", который объединяет два предыдущих метода и проверит надлежащие видимые грани на одной плоскости.

Если вам это удается, мы говорим от 2 до 6 полигонов вместо 96, чтобы отобразить 8 кубов.

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

Есть, вероятно, тонна документов, созданных с помощью Minecraft, несколько поисковых роботов помогут вам разобраться!