2013-01-13 94 views
0

我想檢查內部着色器(GLSL)如果我的vec4是NULL。我需要這樣做的原因有很多,主要是爲了獲得特定的圖形卡兼容,因爲它們中的一些在gl_FragColor中傳遞了以前的顏色,而另一些則沒有(提供需要被覆蓋的空vec4)。 好了,一個相當新的Mac,有人得到這個錯誤:在GLSL NULL檢查

java.lang.RuntimeException: Error creating shader: ERROR: 0:107: '==' does not operate on 'vec4' and 'int' 
ERROR: 0:208: '!=' does not operate on 'mat3' and 'int' 

這是我在片段着色器代碼:

void main() 
{ 
    if(gl_FragColor == 0) gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); //Line 107 
    vec4 newColor = vec4(0.0, 0.0, 0.0, 0.0); 

    [...] 

    if(inverseViewMatrix != 0) //Line 208 
    { 
     [do stuff with it; though I can replace this NULL check with a boolean] 
    } 

    [...] 

    gl_FragColor.rgb = mix(gl_FragColor.rgb, newColor.rgb, newColor.a); 
    gl_FragColor.a += newColor.a; 
} 

正如你所看到的,我做了一個0/NULL檢查gl_FragColor在開始時,因爲有些圖形卡在那裏傳遞了有價值的信息,但有些卻沒有。現在,在那個特殊的mac上,它不起作用。我做了一些研究,但找不到有關如何在GLSL中進行適當NULL檢查的任何信息。是否還有一個,還是我真的需要在這裏製作單獨的着色器?

+1

我不認爲GLSL中的矢量數據類型可以爲NULL。與C/C++中可以爲NULL的指針和Java中的引用不同,它們總是一些東西。 –

+0

好吧,除非我也改變了別的東西,那NULL檢查正是解決了一些其他圖形卡上的錯誤(與alpha相關)的問題。它也適用於大多數,所以我不能想象爲什麼它不會在這個?我只能猜測它總是會在vec4 - int比較中返回false ... =/ – Ivorius

回答

9

所有用於閱讀的變量,即輸入變量始終提供合理的值。作爲輸出變量,gl_FragColor不是這些變量之一!

在這段代碼

void main() 
{ 
    if(gl_FragColor == 0) gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); //Line 107 
    vec4 newColor = vec4(0.0, 0.0, 0.0, 0.0); 

你做的第一件事情是從gl_FragColor閱讀。所述GLSL說明書明確規定,即一個輸出varialbe作爲gl_FragColor的值時,輸入的片段着色器級(點),則未定義:

The value of an output variable will be undefined in any of the three following cases:

  1. At the beginning of execution.
  2. At each synchronization point, unless
    • the value was well-defined after the previous synchronization point and was not written by any invocation since, or
    • the value was written by exactly one shader invocation since the previous synchronization point, or
    • the value was written by multiple shader invocations since the previous synchronization point, and the last write performed by all such invocations wrote the same value.
  3. When read by a shader invocation, if
    • the value was undefined at the previous synchronization point and has not been writen by the same shader invocation since, or
    • the output variable is written to by any other shader invocation between the previous and next synchronization points, even if that assignment occurs in code following the read.

一個輸出變量的元素只有在已經被首次寫入其價值被定義。所以你在那裏做的所有事情都沒有意義。它「不起作用」是完全可以允許的,並且是你的錯誤。

您正在調用未定義的行爲,從技術上講,允許您的計算機變得有聲望,在街上追逐您並刪除所有數據,作爲對此的替代反應。


在GLSL一個vec4是一個普通的數據類型,就像INT。它不是某種指向可能是空指針的數組的指針。最好它有一些默認值不會被glUniform的調用覆蓋。

+0

嗯,我確信這個檢查可以解決另一臺計算機上的問題。閱讀你的解釋,我會再次檢查 - 也許是我做了一些其他的改變,解決了這個問題。無論如何感謝您的回答! – Ivorius

+0

@Ivorius:爲什麼你想從gl_FragColor讀取第一個地方?如果你嘗試實現一些多通道渲染方案,你應該使用一對FBO渲染成交替使用的紋理。 – datenwolf

1

GLSL着色器中的變量總是被定義的(否則,你會得到一個鏈接器錯誤)。如果您沒有提供這些值的數據(通過不加載適當的統一或綁定屬性到屬性變量),那些變量中的值將是未定義的(即垃圾),但是存在。

0

即使您不能有null值值,您也可以測試未定義的變量。這是我用來調試着色器的一個技巧:

... 
    /* First we test for lower range */ 
    if(suspect_variable.x < 0.5) { 
     outColour = vec4(0,1,0,0); /* Green if in lower range*/ 
    } else if(suspect_variable.x >= 0.5) { /*Then for the higher range */ 
     outColour = vec4(1,0,0,0); /* Red if in higher range */ 
    } else { 
     /* Now we have tested for all real values. 
     If we end up here we know that the value must be undefined */ 
     outColour = vec4(0,0,1,0); /* Blue if it's undefined */ 
    } 

你可能會問,什麼可以使變量undefined?超出範圍的數組訪問會導致它不確定;

const int numberOfLights = 2; 
uniform vec3 lightColour[numberOfLights]; 
... 
for(int i = 0; i < 100; i++) { 
    /* When i bigger than 1 the suspect_variable would be undefined */ 
    suspect_variable = suspect_variable * lightColour[i]; 
} 

當您無法訪問真實的調試工具時,使用這種簡單易用的技巧。