2014-12-31 15 views
10

Nell'apprendimento della programmazione grafica 3D per i giochi, ho deciso di iniziare in modo semplice utilizzando l'API 3D di Scene Kit. Il mio primo obiettivo di gioco è stato quello di creare un mimo molto semplificato di MineCraft. Un gioco di soli cubi: quanto può essere difficile.Scene Kit Performance con test del cubo

Di seguito è riportato un ciclo che ho scritto per posizionare una corsa di 100 x 100 cubi (10.000) e la prestazione FPS era abissale (~ 20 FPS). Il mio obiettivo di gioco iniziale è troppo alto per Scene Kit o c'è un modo migliore per avvicinarsi a questo?

Ho letto altri argomenti su StackExchange ma non sento che rispondano alla mia domanda. La conversione dei blocchi di superfici esposte in una singola mesh non funzionerà poiché SCNGeometry è immutabile.

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 2014/12/30: Ho modificato il codice in modo che lo SCNBoxNode viene creata una volta e poi ogni scatola aggiuntiva nella matrice di 100 x 100 viene creato attraverso:

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

Sembra che questo cambiamento abbia aumentato il valore di FPS a ~ 30 fps. Le altre statistiche sono le seguenti (dalle statistiche visualizzate nella SCNView): (? Presumo che ciò è trarre le chiamate)

10K 120K (suppongo questo è facce) 360K (Supponendo che questo è il conteggio dei vertici)

La maggior parte del ciclo di esecuzione è in Rendering (sto stimando il 98%). Il tempo totale del loop è 26.7ms (ahi). Sono in esecuzione su Mac Pro Late 2013 (6-core w/Dual D500 GPU).

Dato che un gioco in stile MineCraft ha un paesaggio che cambia continuamente in base alle azioni dei giocatori, non vedo come posso ottimizzarlo entro i confini di Scene Kit. Una grande delusione perché mi piace molto il framework. Mi piacerebbe sentire le idee di qualcuno su come posso affrontare questo problema - senza quello, sono costretto ad andare con OpenGL.

UPDATE 2014/12/30 @ 14:00 ET: Sto vedendo un notevole miglioramento delle prestazioni quando si utilizza flattenedClone(). L'FPS ora è un solido 60fps anche con più caselle e due chiamate di disegno. Tuttavia, l'adattamento di un ambiente dinamico (come supporta MineCraft) si sta ancora rivelando problematico - vedi sotto.

Dato che la matrice cambierebbe la composizione nel tempo, ho aggiunto un gestore keyDown per aggiungere un array di box ancora più grande all'unità esistente e cronometrato la differenza tra l'aggiunta della serie di riquadri risultante in un numero di chiamate molto maggiore rispetto all'aggiunta come una chiave piatta. Ecco cosa ho trovato:

Su keyDown aggiungo un altro array di 120 x 120 caselle (14.400 scatole)

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

Calling flattenedClone() ancora una volta è 4x più lento di quello di aggiungere l'array.

Questo risulta in due chiamate di disegno con 293 K facce e 878 K vertici. Sto ancora giocando con questo e aggiornerò se trovo qualcosa di nuovo. In conclusione, con i miei test aggiuntivi sento ancora i vincoli geometrici immutabili di Scene Kit che non posso sfruttare la struttura.

+1

In che ambiente si prova? Dov'è il collo di bottiglia delle prestazioni? Vedi la costruzione di un gioco con TalkKit talk [dal WWDC 2014] (http://developer.apple.com/videos/wwdc/2014) per suggerimenti su come rintracciare quest'ultimo. – rickster

+2

non conosco il set di scene ma generalmente l'approccio "ingenuo" sarà piuttosto lento. Considera che un gioco come Minecraft probabilmente non garantisce il rendering di blocchi completamente nascosti da altri, che implementa l'istanziamento (disegnando gli stessi blocchi in un colpo solo) e altre ottimizzazioni generali e specifiche del gioco. SceneKit è un renderizzatore generico, quindi dovrai provare a vedere quale tipo di ottimizzazioni possono essere implementate e cosa funziona meglio per SceneKit. Se si determina che è necessario un controllo di livello più basso, potrebbe essere necessario ripristinare GLKit o OpenGL non elaborato. – LearnCocos2D

+2

Le chiamate 10K per disegnare sono * troppo * troppo. Prova a mirare a qualcosa più vicino a 100. Puoi ridurre notevolmente il numero di richiami disegnando appiattendo la geometria ('flattenedClone()'). Se una casella dovesse essere successivamente separata dall'azione di un utente, tratterei quella casella su quell'azione e non lascerò l'intera scena in uno stato separato, solo perché l'utente potrebbe interagire con essa. –

risposta

0

Come hai menzionato Minecraft, penso che valga la pena di vedere come funziona.

Non ho dettagli tecnici o codice di esempio per voi, ma tutto dovrebbe essere abbastanza straightfoward:

Avete mai giocato a minecraft online, e il terreno non viene caricato che consente di vedere fino in fondo? Questo perché non c'è nessuna geometria all'interno.

supponiamo di avere una matrice 2x2x2 di cubi. Ciò rende 2 * 2 * 2 * 6 * 2 = 96 triangoli.

Tuttavia, se si prova e si disegnano solo i poligoni sul visibile dal punto di vista della telecamera, magari testando le normali (facile poiché si tratta di cubi), questo numero scende a 48 triangoli.

Se trovi un modo per vedere quali facce sono occluse da altre (che non dovrebbe essere troppo difficile considerando che stai lavorando con facce piatte, in quarta, a griglia) puoi solo disegnarle. in questo modo, stiamo disegnando tra 8 e 24 triangoli. Ottimizzazione fino al 90%.

Se si desidera ottenere una profondità davvero elevata, è possibile persino combinare le facce, per creare un singolo N-gon dalle facce piatte visibili. Puoi farlo se crei un nuovo modo per generare al volo la geometria che combina i due metodi precedenti e testare le facce visibili adiacenti sullo stesso piano.

Se riesci, stiamo parlando da 2 a 6 poligoni invece di 96, per rendere 8 cubi.

Si noti che l'ultimo metodo funziona solo se i blocchi si toccano.

Probabilmente c'è una tonnellata di documenti di rendering di Minecraft, alcuni googles ti aiuteranno a capirlo!

+0

Sono d'accordo con i tuoi commenti Moustach ma la sfida con questo approccio è la classe SCNGeometry. Supporta tutto ciò che hai detto ma è immutabile. Quindi dovresti creare una mesh per SCNGeometry che rappresenti il ​​terreno, e non appena qualcosa cambia ti butti quella mesh (sto scommettendo un enorme ciclo di rilascio della memoria) e ricrea tutto per accomodare solo una piccola modifica di "blocco". –

+0

Vero, ma puoi usare l'approccio di Minecraft sull'uso di "Chunk". Separando la geometria in vari elementi, è possibile testarli singolarmente e verificare se è necessario aggiornarli considerando il POV corrente.A meno che l'utente non si muova molto velocemente, un Chunk non dovrebbe essere aggiornato più di ogni pochi fotogrammi considerando che una singola mesh generata può essere utilizzata per molti punti di vista. Non è possibile anche eseguire il rendering di oggetti completi, ma ottimizzarli ancora combinando poligoni complanari e liberando la geometria interna. – Moustach

+0

Se guardi qualcuno che suona 'Minecraft' bene ', ciò che mi stupisce è quanto rapidamente si muovono, e quanto Minecraft sia incredibilmente reattivo. Penso che parte della sua attrazione duratura sia che è incredibilmente performante. Raramente c'è un fastidio per l'esperienza dell'utente in termini di rallentamento. Anche i menu per gli elementi pop e scambiano a velocità straordinaria. – Confused