在OpenGLES中组合多个着色器

时间:2012-04-12 21:26:57

标签: ios opengl-es filter shader

我有一个代码,我收到YUV频道,我正在使用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 个答案:

答案 0 :(得分:1)

Sharpen是一个卷积滤波器,因此它读取九个输入值以产生一个输出值。因此,如果你有另一个应该在它之前出现的着色器并且一次操作一个像素,那么就可以通过两个步骤运行它们(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;
}