Il concetto
Fondamentalmente, un grafico di scena non è altro che un grafico aciclico bi-diretto che serve a rappresentare un insieme strutturato di relazioni spaziali gerarchicamente.
I motori in natura tendono ad includere altre chicche nel grafico della scena, come notato. Se la vedi come la carne o la mucca probabilmente dipende dalla tua esperienza con i motori e le librerie là fuori.
Mantenerlo leggero
Preferisco lo stile Unity3D di avere il tuo nodo grafico di scena (che al suo centro è una struttura topologica piuttosto che una struttura spaziale / topografica) include intrinsecamente parametri e funzionalità spaziali. Nel mio motore, i miei nodi sono persino più leggeri di Unity3D, dove ereditano molti membri inutili di spazzatura da superclassi / interfacce implementate: ecco cosa ho - più leggero che puoi ottenere:
- membri del puntatore padre / figlio.
- pre-trasforma i membri dei parametri spaziali: posizione xyz, inclinazione, imbardata e rollio.
- una matrice di trasformazione; le matrici in una catena gerarchica possono moltiplicarsi molto rapidamente e facilmente camminando ricorsivamente su / giù dall'albero, dandoti le trasformazioni spaziali gerarchiche che sono la caratteristica principale di un grafico di scena;
- un
updateLocal()
metodo che aggiorna solo le matrici di trasformazione di questo nodo
- un
updateAll()
metodo che aggiorna questa e tutte le matrici di trasformazione dei nodi discendenti
... Includo anche la logica delle equazioni di movimento e quindi i membri di velocità / accelerazione (lineari e angolari) nella mia classe di nodi. Puoi rinunciare a questo e gestirlo nel tuo controller principale invece se lo desideri. Ma questo è tutto - molto leggero davvero. Ricorda, potresti averli su migliaia di entità. Quindi, come hai suggerito, tienilo leggero.
Costruire Gerarchie
Cosa dici di un grafico di scena che fa riferimento ad altri grafici di scena ... Sto aspettando la battuta finale? Certo che lo fanno. Questo è il loro uso principale. È possibile aggiungere qualsiasi nodo a qualsiasi altro nodo e le trasformazioni dovrebbero avvenire automaticamente nello spazio locale della nuova trasformazione. Tutto quello che stai facendo è cambiare un puntatore, non è come se stessi copiando i dati! Modificando un puntatore, si ottiene quindi un grafico della scena più profondo. Se usare i proxy rende le cose più efficienti, allora non ne ho mai visto la necessità.
Evita la logica relativa al rendering
Dimentica il rendering mentre scrivi la classe del nodo del grafico della scena, o confonderai le cose per te stesso. Tutto ciò che conta è che tu abbia un modello di dati - che si tratti o meno del grafico della scena - e che alcuni renderer ispezioneranno quel modello di dati e renderizzeranno gli oggetti nel mondo di conseguenza, sia che siano in 1, 2 , 3 o 7 dimensioni. Il punto che sto sottolineando è: non contaminare il grafico della scena con la logica di rendering. Un grafico di scena riguarda la topologia e la topografia, ovvero la connettività e le caratteristiche spaziali. Questi sono il vero stato della simulazione ed esistono anche in assenza di rendering (che può assumere qualsiasi forma sotto il sole da una vista in prima persona a un grafico statistico a una descrizione testuale). I nodi non puntano a oggetti correlati al rendering, tuttavia potrebbe essere vero il contrario. Considera anche questo: Non tutti i nodi del grafico della scena nell'intero albero saranno renderizzabili. Molti saranno solo contenitori. Quindi perché allocare memoria anche per un puntatore a render-object? Anche un membro puntatore che non viene mai utilizzato, sta ancora occupando memoria. Quindi invertire la direzione del puntatore: l'istanza relativa al rendering fa riferimento al modello di dati (che potrebbe essere o includere il nodo del grafico della scena), NON viceversa. E se vuoi un modo semplice per scorrere l'elenco dei controller e ottenere l'accesso alla vista correlata, usa un dizionario / tabella hash, che si avvicina al tempo di accesso in lettura O (1). In questo modo non c'è contaminazione e la tua logica di simulazione non si preoccupa dei renderer presenti, il che rende i tuoi giorni e le tue notti di programmazione Quindi perché allocare memoria anche per un puntatore a render-object? Anche un membro puntatore che non viene mai utilizzato, sta ancora occupando memoria. Quindi invertire la direzione del puntatore: l'istanza relativa al rendering fa riferimento al modello di dati (che potrebbe essere o includere il nodo del grafico della scena), NON viceversa. E se vuoi un modo semplice per scorrere l'elenco dei controller e ottenere l'accesso alla vista correlata, usa un dizionario / tabella hash, che si avvicina al tempo di accesso in lettura O (1). In questo modo non c'è contaminazione e la tua logica di simulazione non si preoccupa dei renderer presenti, il che rende i tuoi giorni e le tue notti di programmazione Quindi perché allocare memoria anche per un puntatore a render-object? Anche un membro puntatore che non viene mai utilizzato, sta ancora occupando memoria. Quindi invertire la direzione del puntatore: l'istanza relativa al rendering fa riferimento al modello di dati (che potrebbe essere o includere il nodo del grafico della scena), NON viceversa. E se vuoi un modo semplice per scorrere l'elenco dei controller ma ottenere l'accesso alla vista correlata, usa un dizionario / tabella hash, che si avvicina a O (1) tempo di accesso in lettura. In questo modo non c'è contaminazione e la tua logica di simulazione non si preoccupa dei renderer presenti, il che rende i tuoi giorni e le tue notti di programmazione E se vuoi un modo semplice per scorrere l'elenco dei controller ma ottenere l'accesso alla vista correlata, usa un dizionario / tabella hash, che si avvicina a O (1) tempo di accesso in lettura. In questo modo non c'è contaminazione e la tua logica di simulazione non si preoccupa dei renderer presenti, il che rende i tuoi giorni e le tue notti di programmazione E se vuoi un modo semplice per scorrere l'elenco dei controller ma ottenere l'accesso alla vista correlata, usa un dizionario / tabella hash, che si avvicina a O (1) tempo di accesso in lettura. In questo modo non c'è contaminazione e la tua logica di simulazione non si preoccupa dei renderer presenti, il che rende i tuoi giorni e le tue notti di programmazionemondi più facili.
Per quanto riguarda l'abbattimento, fare riferimento a quanto sopra. L'abbattimento dell'area di interesse è un concetto logico di simulazione. Cioè, non elabori il mondo al di fuori di quest'area (solitamente inscatolata, circolare o sferica). Ciò avviene nel controller principale / loop di gioco, prima che avvenga il rendering. D'altra parte, l'abbattimento del frustum è puramente correlato al rendering. Quindi dimentica di abbattere subito. Non ha nulla a che fare con i grafici delle scene e, concentrandoti su di essa, oscurerai il vero scopo di ciò che stai cercando di ottenere.
Una nota finale ...
Ho la forte sensazione che tu provenga da uno sfondo Flash (in particolare AS3), dati tutti i dettagli sul rendering inclusi qui. Sì, il paradigma Flash Stage / DisplayObject include tutta la logica di rendering come parte dello scenario. Ma Flash fa molte ipotesi che non vuoi necessariamente fare. Per un motore di gioco completo, è meglio non mescolare i due, per motivi di prestazioni, convenienza e controllo della complessità del codice attraverso un SoC adeguato .