Sto scrivendo un 3D raytracer come progetto di apprendimento personale (Enlight) e ho riscontrato un problema interessante relativo ai test di intersezione tra un raggio e una scena di oggetti.Struttura dati/approccio per raytracing efficiente
La situazione è:
- Ho un certo numero di primitive che i raggi può intersecarsi con (sfere, scatole, aerei, ecc) e gruppi di essi. Collettivamente chiamerò questi oggetti scena.
- Desidero essere in grado di eseguire il rendering degli oggetti primitivi con trasformazioni arbitrarie affini avvolgendoli in un oggetto
Transform
(importante, questo consentirà di utilizzare più istanze delle stesse primitive in posizioni diverse nella scena poiché i primitivi sono immutabili) - oggetti Scene possono essere memorizzati in una gerarchia volume di delimitazione (cioè sto facendo partizionamento spaziale)
- miei test intersezione lavorano con
Ray
oggetti che rappresentano un segmento raggio parziale (iniziare vettore, direzione vettore normalizzato, inizia distanza , distanza finale)
Il problema è che quando un raggio colpisce il riquadro di delimitazione di un oggetto Transform, sembra che l'unico modo per eseguire un test di intersezione con le primitive trasformate contenute sia trasformare lo Ray
nello spazio di coordinate trasformate. Questo è abbastanza facile, ma se il raggio non colpisce alcun oggetto trasformato, devo ricorrere allo Ray
originale per continuare la traccia. Poiché Transforms può essere annidato, ciò significa che devo mantenere un'intera pila di Ray
s per ogni traccia di intersezione che viene eseguita.
Questo è naturalmente all'interno del ciclo interno dell'intera applicazione e del collo di bottiglia principale delle prestazioni. Verrà chiamato milioni di volte al secondo, quindi mi preme minimizzare la complessità/evitare allocazioni di memoria non necessarie.
Esiste un modo intelligente per evitare di dover allocare nuovo Ray
s/mantenere uno stack Ray
?
O c'è un modo più intelligente di fare tutto questo?
Non sono sicuro che questo sarebbe più veloce delle allocazioni di memoria, ma potresti provare a creare un efficiente algoritmo di inversione di trasformazione e quindi solo moltiplicare il raggio di corrente con la trasformazione inversa quando si allontana dall'oggetto corrente. –
@ Ivan - idea interessante. Immagino che potrebbe essere leggermente più veloce, anche se sarei preoccupato per la combinazione di problemi di precisione numerica ... – mikera
Puoi pre-calcolare e memorizzare nella cache una trasformazione e una trasformazione inversa (cioè un oggetto matrice) per ogni oggetto (così come oggetti nel gruppo) che convertirà in e dalla cornice globale. In questo modo non hai bisogno di una gerarchia nidificata poiché puoi eseguire direttamente un hit test su ciascun oggetto. Cioè trasforma il raggio nella cornice dell'oggetto, quindi trasformalo indietro per ottenere il punto di impatto nella cornice globale. Lo faccio nel mio tracciante: http://github.com/danieljfarrell/pvtrace –