ios - 在 OpenGLES 中组合多个着色器

标签 ios opengl-es filter shader

我有一个接收 YUV channel 的代码,我正在使用 OpenGLES 绘制它们。基本上,我有一个将它们组合在一起的着色器。

我想为结果添加锐化过滤器(使用以下示例:http://igortrindade.wordpress.com/2010/04/23/fun-with-opengl-and-shaders/)

我不确定如何在实际结果上运行另一个着色器(因为我想在我之前的着色器将所有 channel 组合到一个帧后运行它)。

我当前的代码如下所示:

            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 是包含 channel 的纹理。

最佳答案

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

关于ios - 在 OpenGLES 中组合多个着色器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10132116/

相关文章:

ios - 区域监控(地理围栏)会消耗电池电量 (iOS)

c++ - opengl glDrawArray 抛出异常

android - 从 OBJ 文件导入时如何在 glTexCoordPointer 中设置/计算纹理缓冲区

ios - 如何在 Objective C 中订阅 youtube channel ?

ios - swift 3 + 火力地堡 : Check if value inside array exists?

python - tweepy stream.filter() 方法不能正常工作

python - 在 BeagleBone Black 上使用 numpy(不是 scipy!)编写一个 butterworth 过滤器

javascript - 我无法使用 .filter() 方法来过滤正确的索引

iphone - 仅具有核心动画的 FlipBoard

Cocoa - OpenGL ES - 将我的头围绕在 C 数组上