ios - 构建基于 OpenGL ES 2.0 着色器的动态过滤器链的最佳方法

标签 ios opengl-es-2.0 caeagllayer

我使用的是 iOS 6(如果你愿意的话,也可以是 7)和 GL ES 2.0。 这个想法是让 CAEAGLLayer 有一个动态的基于着色器的过滤器链,处理它的内容属性并显示最终结果。可以在链中的任何位置添加/删除过滤器。

到目前为止,我想出了一个实现,但我想知道是否有更好的方法来实现它。我的实现大致是这样的:

  1. 具体滤镜继承的基本滤镜类,为它们实现的任何滤镜/成像创建着色器程序(顶点/片段组合)。
  2. 一个 CAEAGLLayer 子类,它实现过滤器链并向其添加过滤器。高级处理算法是:

     // 1 - Assume whenever the layer's content property is changed to an image, a copy of the image gets stored in a sourceImage property.
     // 2 - Assume changing the content property or adding / removing an image unit triggers this algorithm.
     // 3 - Assume the whole filter chain basically processes a quad with position and texture coordinates thru a VBO.
     // 4 - Assume all shader programs (by shader program I mean a vertex and fragment shader pair in a single program) have access to texture unit 0.
     // 5 - Assume P shader programs.
    
     load imageSource into a texture object bound to GL_TEXTURE2D and pointing to to GL_TEXTURE0
     attach bound texture object to GL_FRAMEBUFFER GL_COLOR_ATTACHMENT0 (so we are doing render-to-texture, which will be accessible to fragment shaders)
     for p = program identifier 0 up to P - 2:
        glUseProgram(p)
        glDrawArrays()
    
     attach GL_RENDERBUFFER to GL_FRAMEBUFFER GL_COLOR_ATTACHMENT0 (GL_RENDERBUFFER in turn has its storage set to the layer itself);
     p = program identifier P - 1 (last program in the chain)
     glUseProgram(p)
     glDrawArrays()
    
     present GL_RENDERBUFFER onscreen
    

到目前为止,这种方法似乎行得通,但有很多事情我想知道:

实现添加/删除过滤器的最佳方式:

添加和删除程序似乎是目前最合乎逻辑的方法。然而,这意味着每个插件一个程序,并在渲染时在所有这些插件之间切换。我想知道这些其他方法如何比较:

  1. 附加/分离着色器对并重新链接单个复合程序,而不是添加/删除程序。 OpenGL ES 2.0 编程指南说你不能这样做。但是,由于桌面 GL 允许在一个程序中使用多个着色器对象,所以我很好奇如果 ES 支持它是否会是一种更好的方法。
  2. 将过滤器保持为文本格式(它们的代码在 main 之外的函数中),而是将它们全部编译成一个整体着色器对(当然添加了 main ) 每次添加/删除过滤器时。

实现每个过滤器缓存的最佳方式:

现在,在链中的任何一点添加/删除任意数量的滤镜都需要再次运行所有程序以渲染最终图像。但是,如果我能以某种方式缓存每个过滤器的输出,那就太好了。这样,删除、添加或绕过过滤器只需要运行过滤器经过链中的插入/删除/绕过点。我可以想到一个天真的方法:在每个程序传递中,将不同的纹理对象绑定(bind)到 GL_TEXTURE0 和帧缓冲区的 GL_COLOR_ATTACHMENT0。这样我就可以保留每个过滤器的输出。但是,创建新纹理、绑定(bind)和更改每个过滤器一次的帧缓冲区附件似乎效率低下。

最佳答案

filter输出缓存问题我就不多说了,至于filter切换... EXT_separate_shader_objects扩展旨在解决这个问题,运行 iOS 5.0 或更高版本的所有设备都支持它。以下是简要概述:

  1. 有一个新的方便的 API 用于编译着色器程序,它还负责使它们“可分离”:

    _vertexProgram = glCreateShaderProgramvEXT(GL_VERTEX_SHADER, 1, &source);
    
  2. 程序管道对象管理您的程序状态,让您混合和匹配已编译的着色器:

    GLuint _ppo;
    glGenProgramPipelinesEXT(1, &_ppo);
    glBindProgramPipelineEXT(_ppo);
    glUseProgramStagesEXT(_ppo, GL_VERTEX_SHADER_BIT_EXT, _vertexProgram);
    glUseProgramStagesEXT(_ppo, GL_FRAGMENT_SHADER_BIT_EXT, _fragmentProgram);
    
  3. 混合和匹配着色器会使属性绑定(bind)变得很痛苦,因此您可以在着色器中指定(对于 varyings 也是如此):

    #extension GL_EXT_separate_shader_objects : enable
    layout(location = 0) attribute vec4 position;
    layout(location = 1) attribute vec3 normal;
    
  4. Uniforms 是为它们所属的着色器程序设置的:

    glProgramUniformMatrix3fvEXT(_vertexProgram, u_normalMatrix, 1, 0, _normalMatrix.m);
    

关于ios - 构建基于 OpenGL ES 2.0 着色器的动态过滤器链的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18434510/

相关文章:

ios - 通过一个容器 View 传递多个 View Controller - Xcode 8,Swift 3

android - 在 Android、OpenGL 中,我想使用以中心为设备屏幕中点的运动事件动态绘制一个圆,但没有获得所需的输出

objective-c - OpenGL ES 2.0 纹理映射,但显示为黑色

android - 适用于 Android 的 OpenGL ES 2.0 翻译 - 似乎弄乱了矩阵

ios - 如何使用 openGL 上下文 : Current draw framebuffer is invalid 设置 CAEAGLLayer 子类

ios - 如何使用协议(protocol)扩展为类提供自动生成的标识符?

ios - Realm swift 2.0 : "Operation not permitted" - only on device

ios - 如何防止 iOS 应用程序 Hook theOS 或其他