2012-10-04 11 views
5

Apple's Best Practices for OpenGL ES consigliare contro la ramificazione sui risultati calcolati in un framment shader. Ma il Phong shading generalmente comporta il saltare il termine speculare quando la sorgente di luce si trova sul lato "sbagliato" della superficie, per cui l'approccio diretto è puntare la direzione normale dell'unità N e la direzione della luce L e verificare un risultato positivo.Incoerenze dispositivo/sistema operativo in GLSL ES Risultati dello shader Phong

Ho tentato di fare questo senza una filiale nel mio Shader: invece di utilizzare un if dichiarazione, lo faccio tutti i calcoli per il termine speculari e poi dargli un coefficiente che è 1.0 se dot(N, L) è maggiore di zero e 0.0 altrimenti . (I raggiungere questo tramite la funzione built step(). La combinazione di max() e sign() produce gli stessi risultati, ma si dice che sia un po 'più lento.)

Tuttavia, questo è apparso per portare a dispari, dispositivo- e/o iOS versione specifica , i risultati:

with branchwithout branch

  • Sul mio iPhone 4 con iOS 6.0, la versione con il ramo ha una grande luce speculare (immagine a sinistra); senza il ramo vedo una luce speculare stretta (immagine a destra), nonostante l'esponente della "lucentezza" sia lo stesso.
  • Nel simulatore di iOS 6.0, vedo la seconda immagine con entrambe le versioni dello shader.
  • Sul mio iPad (modello originale 2010, bloccato su iOS 5.1), vedo la prima immagine con entrambe le versioni dello shader.

Chiaramente, non è la ramificazione o la mancanza di ciò che è il problema. (L'immagine a destra è la resa "corretto", tra l'altro.)

Ecco il mio frammento di shader:

precision mediump float; 

uniform lowp vec3 ambientLight; 
uniform lowp vec3 light0Color; 
uniform lowp vec3 materialAmbient; 
uniform lowp vec3 materialDiffuse; 
uniform lowp vec3 materialSpecular; 
uniform lowp float materialShininess; 

// input variables from vertex shader (in view coordinates) 
varying vec3 NormDir; 
varying vec3 ViewDir; 
varying vec3 LightDir; 

void main (void) 
{ 
    vec3 L = normalize(LightDir); 
    vec3 N = normalize(NormDir); 
    vec3 E = normalize(ViewDir); 

    lowp vec3 ambient = ambientLight * materialAmbient; 

    float cos_theta = dot(L, N); 

    lowp vec3 diffuse = materialDiffuse * light0Color * max(0.0, cos_theta); 

    lowp vec3 specular = vec3(0.0, 0.0, 0.0); 
// if (cos_theta > 0.0) { 
     lowp vec3 R = reflect(-L, N); 
     lowp vec3 V = normalize(-E); 
     float cos_alpha = dot(R, V); 
     specular = step(0.0, cos_theta) * materialSpecular * light0Color * pow(max(0.0, cos_alpha), materialShininess); 
     //   ~~~~~~~~~~~~~~~~~~~~~~ 
     //   should produce the same results as the commented branch, right? 
// } 
    gl_FragColor = vec4(ambient + diffuse + specular, 1.0); 
} 

accolgo ulteriori suggerimenti per migliorare le prestazioni di questo shader su hardware iOS, anche!

+6

Potrebbe essere un artefatto di precisione? So che ho visto differenze significative nel modo in cui i valori di lowp sono arrotondati tra i vari dispositivi iOS. In particolare, mi chiedo se l'uso di lowp per alcuni dei valori che portano a 'cos_alpha' e' materialShininess' non possa causare strane cose nell'operazione 'pow()'. Non credo che l'uso del mediump ti rallenterebbe troppo. –

+0

Entrambi gli approcci non sono completamente equivalenti. step (0.0, cos_theta) è equivalente a "if (cos_theta> = 0)", come step() restituisce 1 quando cos_theta = 0 perché (0.0 <0) è falso. ma non credo che stia facendo la differenza comunque. –

+4

Ci è voluto del tempo per trovare il tempo di sperimentarlo ancora, ma @BradLarson ha ragione: la precisione su 'materialShininess' è proprio così. Una volta che è 'mediump', le incoerenze del dispositivo/sistema operativo vanno via e tutte rendono il modo" corretto "(immagine a destra). (In realtà, il ramo/roba no-branch si è rivelato essere una falsa pista.) Posta come risposta e accetterò. – rickster

risposta

1

Come notato nel commento di @ BradLarson, il qualificatore lowp su materialShininess si è rivelato essere il problema; con quello impostato su mediump, invece, esegue correttamente il rendering (immagine a destra) su tutti i dispositivi e le versioni del sistema operativo che ho a disposizione, indipendentemente dal fatto che venga utilizzata la versione dello shader del ramo o senza ramo (con step).

(Uso lowp contro mediump per gli ingressi R e V da cui cos_alpha è calcolato non fa alcuna differenza visibile, che ha senso:. Quelli sono vettori normalizzati, così loro componenti hanno magnitudini nell'intervallo 0,0 a 1,0 È la stessa gamma dei componenti di colore, per i quali sembra che sia previsto l'uso di lowp)