2012-04-12 128 views
1

我有一個代碼,我接收YUV通道,並使用OpenGLES繪製它們。基本上,我有一個着色器將它們結合在一起。在OpenGLES中組合多個着色器

我想一個銳化濾鏡添加到結果(使用下面的例子:http://igortrindade.wordpress.com/2010/04/23/fun-with-opengl-and-shaders/

我不知道如何運行的實際結果的另一個着色器(因爲我想以後運行它我以前的着色器將所有通道合併到一個幀中)。

我當前的代碼看起來像這樣:

  glUniform1i(texLum, 0); 
      glUniform1i(texU, 1); 
      glUniform1i(texV, 2); 

      glEnableVertexAttribArray(positionLoc); 
      glVertexAttribPointer(positionLoc, 
            4, 
            GL_FLOAT, 
            GL_FALSE, 
            0, 
            &vertices[0]); 

      glEnableVertexAttribArray(texCoordLoc); 
      glVertexAttribPointer(texCoordLoc, 
            2, 
            GL_FLOAT, 
            GL_FALSE, 
            0, 
            &texCoords[0]); 


      glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]), GL_UNSIGNED_BYTE, &indices[0]); 

我想我需要在最後一行(glDrawElements)前右添加新的着色器,但我不知道如何調用它。

我着色器看起來是這樣的:

static char const *frag = 
    "uniform lowp sampler2D texLum; \n" 
    "uniform lowp sampler2D texU; \n" 
    "uniform lowp sampler2D texV; \n" 
    "varying mediump vec2 texCoordAtFrag; \n" 
    "void main() { \n" 
    " lowp float Y = texture2D(texLum, texCoordAtFrag).r; \n" 
    " lowp float U = texture2D(texU, texCoordAtFrag).r; \n" 
    " lowp float V = texture2D(texV, texCoordAtFrag).r; \n" 
    " lowp float R = 1.164 * (Y - 16.0/256.0) + 1.596 * (V - 0.5); \n" 
    " lowp float G = 1.164 * (Y - 16.0/256.0) - 0.813 * (V - 0.5) - 0.391 * (U - 0.5); \n" 
    " lowp float B = 1.164 * (Y - 16.0/256.0) + 2.018 * (U - 0.5); \n" 
    " gl_FragColor = vec4(R,G,B,1); \n" 
    "}\r\n"; 

    static char const *vert = 
    "varying mediump vec2 texCoordAtFrag; \n" 
    "attribute vec4 Position; \n" 
    "attribute vec2 TexCoord; \n" 
    "void main() { \n" 
    " texCoordAtFrag = TexCoord; \n" 
    " gl_Position = Position; \n" 
    "}\r\n"; 

凡texLum,texU,texV是抱着通道的紋理。

回答

1

銳化是一個卷積過濾器,所以它讀取九個輸入值來產生一個輸出值。因此,如果您有另一個應該在其之前出現的着色器並且一次運行一個像素,則會有一個體面的參數用於分兩步運行它們(先進行YUV變換,再銳化),以消除重複計算,甚至如果它不是將着色器合併爲封閉盒子的最簡單方法。

如果您想將其組合起來,請將YUV轉換分解爲單獨的函數,並使銳化濾鏡調用該函數而不是texture2D。 GL着色器編譯器對源文件的數量沒有任何限制,您可以將它們鏈接在一起以精確編譯編譯的程序,以便您可以按照通常的編程路線進行函數重用。

如果你想運行一個然後運行另一個然後使用中間渲染到紋理階段。進行YUV變換,然後切換緩衝區並將其輸出用作銳化的輸入。

實際上,前者實際上可能比後者更快,因爲YUV變換可能是一種快速操作(例如,如果它是YUV到RGB那麼它是一個矩陣乘法),而內存速度和需要做相當劇烈改變狀態可能相當昂貴。如果性能是一個問題,您可能需要進行配置。

編輯:那麼,從您目前的主,你可能只是適應,要(在此類型的,我走了,請原諒的錯誤):

"uniform lowp sampler2D texLum; \n" 
"uniform lowp sampler2D texU; \n" 
"uniform lowp sampler2D texV; \n" 
"varying mediump vec2 texCoordAtFrag; \n" 
"lowp vec4 yuvTexture2D(mediump vec2 coord) { \n" 
" lowp float Y = texture2D(texLum, coord).r; \n" 
" lowp float U = texture2D(texU, coord).r; \n" 
" lowp float V = texture2D(texV, coord).r; \n" 
" lowp float R = 1.164 * (Y - 16.0/256.0) + 1.596 * (V - 0.5); \n" 
" lowp float G = 1.164 * (Y - 16.0/256.0) - 0.813 * (V - 0.5) - 0.391 * (U - 0.5); \n" 
" lowp float B = 1.164 * (Y - 16.0/256.0) + 2.018 * (U - 0.5); \n" 
" return vec4(R,G,B,1.0); \n" 
"}\r\n 

,然後在銳化濾鏡你會替代通話調用texture2D(<whatever>, coord),調用yuvTexture2D(coord),將片段包含在源代碼清單中用於銳化着色器或將其鏈接到程序中。關於切換到使用矩陣方法,我想你會想(我將格式化爲字符串常量以外的格式,以便於打字):

uniform lowp sampler2D texLum; 
uniform lowp sampler2D texU; 
uniform lowp sampler2D texV; 
varying mediump vec2 texCoordAtFrag; 

const mediump mat4 yuvToRgb = 
mat4( 1.164, 1.164, 1.164, -0.07884, 
     2.018, -0.391, 0.0, 1.153216, 
     0.0, -0.813, 1.596, 0.53866, 
     0.0,  0.0, 0.0, 1.0); 

lowp vec4 yuvTexture2D(mediump vec2 coord) { 
    lowp vec4 yuv = 
     vec4(
      texture2D(texLum, coord).r, 
      texture2D(texU, coord).r, 
      texture2D(texV, coord).r, 
      1.0) 
    return yuvToRgb * yuv; 
} 
+0

我添加了代碼我的着色器。你能指點我如何結合過濾器?我有點困惑,因爲我的代碼一次只做1個像素,我不確定如何將其轉換爲矩陣操作。 – 2012-04-12 22:02:14

+1

@Gilad - 我可以談論將顏色處理操作分解爲兩個獨立着色器並在兩次執行中進行卷積的好處。對於從3x3區域拉入數值的Sobel邊緣檢測濾波器,首先將圖像轉換爲其亮度值,然後拍攝該亮度圖像並對其執行卷積運算,導致iPhone 4的速度提高了10倍,而兩次操作用單一着色器進行一次傳遞。除非內存問題,否則我強烈建議將其分成兩個階段,一個用於YUV-> RGB,另一個用於銳化。 – 2012-04-15 16:09:25

+0

@BradLarson我同意。我已經試過並最終決定分兩階段進行。它產生了一個更容易維護的代碼,結果變得更快。 – 2012-04-16 01:43:17