2014-12-31 20 views
10

Ucząc się programowania grafiki w grach 3D, zdecydowałem się zacząć od prostoty, korzystając z zestawu Scene Kit 3D API. Moim pierwszym celem było zbudowanie bardzo uproszczonego mimika MineCraft. Gra w kostki - jak ciężko może być.Wydajność zestawu scen z testem kostki

Poniżej znajduje się pętla, którą napisałem, aby umieścić jazdę z 100 x 100 kostek (10 000), a wydajność FPS była fatalna (~ 20 FPS). Czy mój początkowy cel gry jest zbyt duży dla Scene Kit, czy jest lepszy sposób, aby się do tego zbliżyć?

Czytałem inne tematy dotyczące StackExchange, ale nie sądzę, aby odpowiedzieć na moje pytanie. Konwersja odsłoniętych bloków powierzchniowych do pojedynczej siatki nie będzie działać, ponieważ parametr SCNGeometry jest niezmienny.

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) 
} 

UPDATE 30.12.2014: I zmodyfikowane kodu tak SCNBoxNode jest tworzony po czym każde dodatkowe pole w macierzy 100 x 100 jest utworzony przez:

var newBoxNode = firstBoxNode.clone() 
newBoxNode.position = SCNVector3Make(x, y, z) 

Wydaje się, że ta zmiana zwiększyła FPS do ~ 30 fps. Pozostałe statystyki przedstawiają się następująco (ze statystyk wyświetlanych w SCNView): (? Zakładam, że jest to narysować połączenia)

10K 120K (zakładam to twarze) 360k (zakładając, że jest to liczba wierzchołków)

Większość pętli uruchamiania znajduje się w trybie renderowania (domyślnie 98%). Całkowity czas pętli to 26,7ms (ouch). Pracuję na komputerze Mac Pro Late 2013 (6-rdzeniowym procesorze graficznym Dual D500).

Biorąc pod uwagę, że gra w stylu MineCraft ma krajobraz, który nieustannie zmienia się w zależności od działań graczy, nie widzę sposobu na zoptymalizowanie tego w ramach zestawu scen. Wielkie rozczarowanie, ponieważ bardzo podoba mi się framework. Chciałbym usłyszeć czyjś pomysł, w jaki sposób mogę rozwiązać ten problem - bez tego jestem zmuszony iść z OpenGL.

AKTUALIZACJA 12-30-2014 @ 2:00 pm ET: Widzę znaczącą poprawę wydajności przy użyciu spłaszczonego Clone(). FPS ma teraz solidne 60 klatek na sekundę, nawet z większą liczbą skrzynek i DWÓCH wywołań rysunkowych. Jednak dostosowanie dynamicznego środowiska (tak jak obsługuje MineCraft) nadal stanowi problem - patrz poniżej.

Ponieważ tablica zmieniłaby skład z biegiem czasu, dodałem procedurę obsługi klucza, aby dodać jeszcze większą tablicę pól do istniejącej i określonej w czasie różnicy między dodaniem tablicy pól, co skutkuje znacznie większymi połączeniami w porównaniu do dodawania jako spłaszczonego klonu. Oto co znalazłem:

Na keyDown dodam kolejną tablicę 120 x 120 pól (14400 pola)

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

Wywoływanie flattenedClone() znowu jest 4x wolniej niż dodanie tablicę.

Powoduje to wykonanie dwóch wywołań rysowania o powierzchni 293K i wierzchołkach 878K. Nadal gram z tym i zaktualizuję, jeśli znajdę coś nowego. Podsumowując, z dodatkowymi testami nadal uważam, że niezmienne geometryczne ograniczenia zestawu scenograficznego oznaczają, że nie mogę wykorzystać struktury.

+1

W jakim środowisku testujesz? Gdzie jest twoje wąskie gardło wydajności? Zobacz temat Budowanie gry z rozmową SceneKit [z WWDC 2014] (http://developer.apple.com/videos/wwdc/2014), aby uzyskać wskazówki dotyczące śledzenia tego ostatniego. – rickster

+2

Nie znam scenekitu, ale ogólnie podejście "naiwne" będzie raczej powolne. Uważają, że gra taka jak Minecraft prawdopodobnie nie powoduje renderowania żadnych bloków, które są całkowicie ukryte przez innych, implementuje instancje (rysowanie tych samych bloków za jednym razem) oraz inne optymalizacje ogólne i związane z grą. SceneKit to renderer ogólnego przeznaczenia, więc będziesz musiał sprawdzić, jakie rodzaje optymalizacji mogą zostać zaimplementowane, a co najlepiej sprawdza się w SceneKit. Jeśli zdecydujesz, że potrzebujesz więcej kontroli niskiego poziomu, powinieneś powrócić do GLKit lub surowego OpenGL. – LearnCocos2D

+2

Połączenia typu "wyciągnij 10K" to * sposób * za dużo. Spróbuj dążyć do czegoś bliższego 100. Możesz znacznie zmniejszyć liczbę wywołań rysowania poprzez spłaszczenie geometrii ('flattenedClone()'). Jeśli jedno pudełko zostanie później oddzielone działaniem użytkownika, zajmie się tym pudełkiem po tej czynności i nie pozostawi całej twojej sceny w stanie oddzielonym, tylko dlatego, że użytkownik może z nią współdziałać. –

Odpowiedz

0

Jak wspomniałeś Minecraft, myślę, że warto przyjrzeć się, jak to działa.

mam żadnych szczegółów technicznych lub próbki kodu dla Ciebie, ale wszystko powinno być dość straightfoward:

Grałeś kiedyś minecraft online, a teren nie jest ładowanie pozwala przejrzeć? To dlatego, że nie ma w nim żadnej geometrii.

Załóżmy, że mam tablicę 2x2x2 kostek. To sprawia, że ​​2 * 2 * 2 * 6 * 2 = 96 trójkątów.

Jeśli jednak przetestujesz i narysujesz tylko wielokąty na widocznym z punktu widzenia kamery, być może testując normalne (łatwe od sześcianu), liczba ta spada do 48 trójkątów.

Jeśli znajdziesz sposób, aby zobaczyć, które twarze są zasłonięte przez inne (które nie powinny być zbyt trudne, biorąc pod uwagę, że pracujesz z płaskimi, ukrytymi twarzami opartymi na siatce), możesz je narysować tylko. w ten sposób pobieramy od 8 do 24 trójkątów. To jest optymalizacja do 90%.

Jeśli chcesz się naprawdę głęboko zagłębić, możesz nawet połączyć twarze, aby pojedynczy N-gon zniknął z widocznych, płaskich twarzy. Możesz to zrobić, jeśli utworzysz nowy sposób generowania geometrii w locie, która łączy dwie poprzednie metody i testuje widzialne twarze na tej samej płaszczyźnie.

Jeśli się powiedzie, mówimy od 2 do 6 wielokątów zamiast 96, aby wyświetlić 8 sześcianów.

Należy pamiętać, że ostatnia metoda działa tylko wtedy, gdy bloki stykają się ze sobą.

Jest prawdopodobnie tona dokumentów w stylu Minecrafta, kilka googlów pomoże Ci to rozgryźć!

+0

Zgadzam się z Twoimi uwagami Moustach, ale wyzwaniem z tym podejściem jest klasa SCNGeometry. Obsługuje wszystko, co powiedziałeś, ale jest niezmienne. Dlatego musielibyśmy stworzyć siatkę dla SCNGeometry reprezentującej teren, a jak tylko coś się zmieni, zrzucić tę siatkę (obstawiam ogromny cykl uwalniania pamięci) i odtworzyć wszystko, aby dostosować się tylko do jednej małej zmiany "bloku". –

+0

To prawda, ale możesz użyć podejścia Minecrafta do używania "Kawałków". Oddzielając geometrię w różnych elementach, można przetestować każdy z nich osobno i sprawdzić, czy trzeba je zaktualizować, biorąc pod uwagę aktualny POV.O ile użytkownik nie porusza się bardzo szybko, porcja nie powinna być aktualizowana częściej niż co kilka ramek, biorąc pod uwagę, że pojedyncza wygenerowana siatka może być użyta dla wielu punktów widzenia. Nie można również renderować pełnych obiektów, ale nadal optymalizować je, łącząc współpłaszczyznowe wielokąty i pozbywając się wewnętrznej geometrii. – Moustach

+0

Jeśli oglądasz kogoś grającego "dobrze" w Minecrafcie, zadziwia mnie, jak szybko się poruszają i jak niesamowicie reaguje Minecraft. Myślę, że częścią jego trwałej atrakcji jest to, że jest niesamowicie wydajna. Rzadko zdarza się irytować użytkownika pod względem spowolnienia. Nawet menu przedmiotów pop i wymiany z niezwykłą prędkością. – Confused