Utilizzo di una LUT per velocizzare uno shader pesante per dispositivi mobili


10

Sto cercando di far funzionare questo shader su un iDevice davvero vecchio, e alla fine anche sugli androidi.

Anche quando riduco il codice fino a 2 funzioni seno per frammento, lo shader funziona a circa 20 fps.

Ho pensato di prendere una foglia dal libro delle vecchie tecniche di shading e creare un array che contiene un mucchio di valori di trigge predefiniti e in qualche modo usarli per approssimare lo shader.

Nello shader che ho collegato sopra sto già simulando che arrotondando i valori inviati alla funzione trig più il mouse a sinistra (mentre in basso) va meno qualità dello shader. In realtà è piuttosto bello perché molto vicino al lato sinistro sembra uno shader completamente diverso e piuttosto bello.

Comunque ho due dilemmi:

  1. Non so quale sia il modo più efficiente per avere una matrice di valori come 360 ​​in uno shader GLSL, costante o uniforme?
  2. Non riesco a capire come inserire un numero in un intervallo come di solito se volessi un angolo compreso tra 0 e 360 ​​(sì, so che le GPU usano i radianti) lo farei così.

    func range(float angle)
    {
       float temp = angle
       while (temp > 360) {temp -= 360;}
       while (temp < 0)   {temp += 360;}
       return temp;
    }
    

    Tuttavia GLSL non consente loop durante o funzioni ricorsive.


Non so se sarebbe pratico implementarlo, ma aiuterebbe a spaziare in modo diseguale i valori sinusoidali precompilati, con valori più strettamente raggruppati in cui la pendenza della curva sinusoidale è più ripida e meno valori in cui si livella e non cambia tanto? Ciò consentirebbe una maggiore precisione dove è necessario, senza la necessità di memorizzare un gran numero di valori?
trichoplax,

5
Per quanto riguarda il numero 2, la modfunzione integrata è ciò che desideri. Scriveresti mod(angle, 360.0).
Nathan Reed,

1
@trichoplax idea geniale ma non so come saresti in grado di cercare i valori sul tavolo allora. Diciamo che li mettiamo in un array con alcuni di loro più concentrati. Come possiamo trovare l'indice giusto?
J.Doe,

6
Che ne dici di mettere i tuoi valori in una trama 1D a 3 canali? In questo modo è possibile ottenere peccato, cos e abbronzarsi per il prezzo di una singola ricerca di texture. Se mappi un angolo da 0 - 2pi a 0 - 1 UV e usi la modalità di trama ripetuta, non hai nemmeno bisogno della mod call, si "avvolge" automaticamente e puoi anche ottenere approssimazioni con filtro lineare tra i valori memorizzati anziché scattando al più vicino.
russ

3
Molte volte è possibile eliminare le funzioni di trigger quando vengono utilizzate per la geometria non utilizzando l'angolo ma iniziare e terminare con la coppia sin / cos e utilizzare le identità di trigge per mezzangoli e simili.
Cricchetto strano

Risposte:


8

[0,360)[0,2π)

  • [0,360][0,1]
  • Ottieni l'ulteriore vantaggio di non dover eseguire la regolazione dell'intervallo simile a un loop (sebbene, non avresti comunque bisogno di loop e potresti semplicemente utilizzare un'operazione di modulo). Basta usare GL_REPEATcome modalità di avvolgimento per la trama e ricomincerà automaticamente dall'inizio quando si accede con argomenti> 1 (e allo stesso modo per argomenti negativi).
  • E ottieni anche il vantaggio di interpolare linearmente tra due valori nell'array praticamente gratuitamente (o diciamo quasi gratis) usando GL_LINEARcome filtro trama, in questo modo ottenendo valori che non hai nemmeno memorizzato. Ovviamente l'interpolazione lineare non è precisa al 100% per le funzioni trigonometriche, ma è certamente meglio di nessuna interpolazione.
  • È possibile memorizzare più di un valore nella trama utilizzando una trama RGBA (o comunque molti componenti necessari). In questo modo è possibile ottenere ad es. Sin e cos con una singola ricerca di texture.
  • [1,1][0,1]float sin = 2.0 * (texValue.r + texValue.g / 256.0) - 1.0;(o anche più componenti per grana più fine). Ciò ti consente di trarre nuovamente profitto dalle trame multicomponente.

Ovviamente deve ancora essere valutato se questa è una soluzione migliore, poiché l'accesso alla trama non è del tutto gratuito, così come quale sarebbe la migliore combinazione di dimensione e formato della trama.

Per quanto riguarda il riempimento della trama con i dati e l'indirizzo di uno dei tuoi commenti, devi considerare che il filtro della trama restituisce il valore esatto al centro del texel , cioè una coordinata della trama fuori della metà della dimensione del texel. Quindi sì, dovresti generare valori in .5texel , cioè qualcosa del genere nel codice dell'applicazione:

float texels[256];
for(unsigned int i = 0; i < 256; ++i)
    texels[i] = sin((i + .5f) / 256.f) * TWO_PI);
glTexImage1D(GL_TEXTURE_1D, 0, ..., 256, 0, GL_RED, GL_FLOAT, texels);

uniform float sinTable[361]glUniform1fv[0,360)mod

angle = mod(angle, 360.0);
float value = sinTable[int(((angle < 0.0) ? (angle + 360.0) : angle) + 0.5)];

1
Ecco un'estensione interessante per la memorizzazione di tabelle di ricerca nelle trame. (Ab) usa l'interpolazione di trama N-lineare per ottenere interpolazione di ordine superiore (meglio o lineare) di punti dati, superfici, volumi e ipervolumi. blog.demofox.org/2016/02/22/…
Alan Wolfe,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.