2012-10-04 17 views
5

Apple's Best Practices for OpenGL ES建議針對片段着色器中計算的結果進行分支。但是Phong shading通常涉及在光源位於表面的「錯誤」一側時跳過鏡面術語,爲此直接方法是將單位法線方向點N和光線方向L並檢查陽性結果。GLSL ES Phong着色器結果中的設備/操作系統不一致性

我試圖這樣做沒有在我的着色器的一個分支:而不是使用if聲明,我做所有的計算了鏡面項,然後給它一個係數,它是1.0如果dot(N, L)大於零且0.0否則更大。 (I實現此使用內置step()功能。結合max()sign()產生相同的結果,但被認爲是慢一點。)

然而,這似乎導致奇數,裝置 - 和/或IOS版本特定,結果:

with branchwithout branch

  • 在我的iPhone 4運行iOS 6.0,與分支版本具有廣泛的鏡面高光(左圖);儘管「光澤度」指數保持不變,但沒有分支我會看到較窄的鏡面高光(右圖)。
  • 在iOS 6.0模擬器上,我看到了具有兩種着色器版本的第二張圖像。
  • 在我的iPad上(原來的2010款型號,卡在iOS 5.1),我看到了兩個着色器版本的第一張圖片。

顯然,這不是分支或缺乏問題。 (右邊的圖像是「正確」的渲染,順便說一句。)

這裏是我的片段着色器:

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); 
} 

我歡迎爲改善這種着色器的iOS上的硬件性能進一步建議,太!

+6

這是一個精確的工件嗎?我知道我看到了各種iOS設備之間lowp值四捨五入方式的重大差異。特別是,我想知道在'pow()'操作中使用lowp來引導'cos_alpha'和'materialShininess'的某些值不會導致奇怪的事情發生。我不認爲在那裏使用中性會減慢你太多。 –

+0

兩種方法都不完全等效。 (0.0,cos_theta)等於「if(cos_theta> = 0)」,因爲(0.0 <0)爲假,因爲當cos_theta = 0時,step()返回1。但我不認爲這是造成差異無論如何。 –

+4

我花了一段時間才找到時間來試試這個,但@BradLarson是正確的:'materialShininess'上的精度就是這樣。一旦這是'中立',設備/操作系統的不一致就會消失,並且全都呈現「正確」的方式(右側圖像)。 (真的,分支/不分行的東西竟然是一隻紅鯡魚。)作爲回答,我會接受。 – rickster

回答

1

正如@ BradLarson的評論所指出的那樣,限定符materialShininess原來是問題;如果設置爲mediump,則無論是使用分支還是不分支(使用step)版本的版本,它都可以在我手頭上的所有設備和操作系統版本上正確呈現(右側圖像)。

(使用lowpmediump用於從cos_alpha計算沒有任何可見的差別輸入RV,這是有意義的:這些是​​歸一化的矢量,因此它們的部件在0.0〜1.0的範圍內具有量值這就是與顏色組件的範圍相同,其中lowp似乎是打算使用的。)