Attualmente sto sviluppando un motore di gioco che utilizza campi di distanza con segno come tecnica di rendering per visualizzare una geometria procedurale uniforme (generata per ora con primitivi semplici come quelli nel tuo link, cercando di implementare i frattali Julia e IFS in futuro). Dato che il mio motore è incentrato sulla generazione procedurale e deve definire le figure in modo da renderle amichevoli per i ray-marcher, immagino di essere in un buon posto per rispondere a questa domanda: P.
Per quanto riguarda lo streaming, la semplice soluzione è utilizzare un buffer tipizzato di qualche tipo e lanciarlo sulla GPU quando si desidera eseguire il ray-marking. Ogni elemento del buffer è un tipo complesso (ad es. Una struttura in C / C ++) e ogni tipo contiene elementi che definiscono quale funzione si dovrebbe usare per rappresentarlo, la sua posizione, rotazione, scala, ecc. E un colore medio. Il processo si semplifica quindi fino a:
- Abbatti la tua scena in un sottoinsieme gestibile (nota che l'abbattimento del frustum e l'abbattimento dell'occlusione sono comunque parzialmente eseguiti automaticamente dall'algoritmo di marcia del raggio)
- Passa il sottoinsieme nel buffer di input del rendering
- Passa il buffer alla GPU se non è già presente, quindi esegui il rendering della tua scena con il normale ray-marking tradizionale. Dovrai eseguire un tipo di ricerca per passaggio per valutare quale elemento nel buffer di input è più vicino a ciascun raggio per ogni iterazione del ray-marcher e dovrai applicare trasformazioni a entrambi i raggi (nel qual caso dovrai invertire le rotazioni delle figure prima che raggiungano la GPU) o le funzioni di distanza stesse (spostando l'origine della funzione per i cambi di posizione, regolando ad esempio le lunghezze dei lati cubi per i cambiamenti di scala, ecc.) L'approccio più semplice è semplicemente modificare i raggi prima li si passa alla funzione di distanza del nucleo attuale.
Per quanto riguarda i colori delle figure, ricorda che gli shader ti consentono di definire tipi complessi e primitivi;). Ciò ti consente di gettare tutto in una struttura in stile C, quindi passare quelle strutture indietro dalla tua funzione di distanza.
Nel mio motore, ogni struttura contiene una distanza, un colore e un ID che lo lega alla definizione della figura corrispondente nel buffer di input. Ogni ID viene dedotto dal contesto circostante della relativa funzione di distanza (poiché la mia funzione di mappatura scorre attraverso il buffer di input per trovare la figura più vicina a ciascun raggio per ogni passaggio, posso tranquillamente trattare il valore del contatore di loop quando viene chiamato ogni SDF come ID della figura per quella funzione), mentre i valori di distanza sono definiti usando un SDF core arbitrario (espoint - figure.pos
per una sfera) e i colori sono definiti dal colore medio dell'elemento appropriato nel buffer delle figure (quindi perché è utile mantenere l'ID della figura attorno) o attraverso un colore procedurale ponderato rispetto alla media memorizzata (un esempio potrebbe essere prendere un conteggio di iterazioni per un certo punto sul Mandelbulb, mappando il tuo "colore medio" dallo spazio colore FP allo spazio colore intero, quindi usando il colore mappato come una tavolozza XOR 'confrontandolo con il conteggio iterazione).
Le trame procedurali sono un altro approccio, ma non le ho mai usate da solo. iq ha svolto molte ricerche in quell'area e pubblicato alcune interessanti dimostrazioni su Shadertoy, quindi potrebbe essere un modo per raccogliere alcune informazioni extra.
Indipendentemente dal fatto che il colore sia statico per ogni figura, generato proceduralmente o magicamente campionato da una trama procedurale, la logica di base è la stessa: figure astratte in una sorta di tipo complesso intermedio (ad esempio una struttura), memorizzare sia la distanza locale che locale colora un'istanza di quel tipo, quindi passa il tipo complesso come valore di ritorno dalla tua funzione di distanza. A seconda dell'implementazione, il colore di output può quindi passare direttamente allo schermo o seguire il punto di collisione nel codice di illuminazione.
Non so se quanto sopra fosse abbastanza chiaro o no, quindi non preoccuparti di chiedere se qualcosa non ha senso. Non posso davvero fornire alcun esempio di codice GLSL / pixel-shading poiché sto lavorando con HLSL e l'ombreggiatura del calcolo, ma sono felice di provare a ripassare tutto ciò che non ho scritto correttamente in primo luogo :).