我使用的是 iOS 6(如果你愿意的话,也可以是 7)和 GL ES 2.0。 这个想法是让 CAEAGLLayer 有一个动态的基于着色器的过滤器链,处理它的内容属性并显示最终结果。可以在链中的任何位置添加/删除过滤器。
到目前为止,我想出了一个实现,但我想知道是否有更好的方法来实现它。我的实现大致是这样的:
- 具体滤镜继承的基本滤镜类,为它们实现的任何滤镜/成像创建着色器程序(顶点/片段组合)。
一个 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
到目前为止,这种方法似乎行得通,但有很多事情我想知道:
实现添加/删除过滤器的最佳方式:
添加和删除程序似乎是目前最合乎逻辑的方法。然而,这意味着每个插件一个程序,并在渲染时在所有这些插件之间切换。我想知道这些其他方法如何比较:
- 附加/分离着色器对并重新链接单个复合程序,而不是添加/删除程序。 OpenGL ES 2.0 编程指南说你不能这样做。但是,由于桌面 GL 允许在一个程序中使用多个着色器对象,所以我很好奇如果 ES 支持它是否会是一种更好的方法。
- 将过滤器保持为文本格式(它们的代码在
main
之外的函数中),而是将它们全部编译成一个整体着色器对(当然添加了main
) 每次添加/删除过滤器时。
实现每个过滤器缓存的最佳方式:
现在,在链中的任何一点添加/删除任意数量的滤镜都需要再次运行所有程序以渲染最终图像。但是,如果我能以某种方式缓存每个过滤器的输出,那就太好了。这样,删除、添加或绕过过滤器只需要运行过滤器经过链中的插入/删除/绕过点。我可以想到一个天真的方法:在每个程序传递中,将不同的纹理对象绑定(bind)到 GL_TEXTURE0
和帧缓冲区的 GL_COLOR_ATTACHMENT0
。这样我就可以保留每个过滤器的输出。但是,创建新纹理、绑定(bind)和更改每个过滤器一次的帧缓冲区附件似乎效率低下。
最佳答案
filter输出缓存问题我就不多说了,至于filter切换... EXT_separate_shader_objects扩展旨在解决这个问题,运行 iOS 5.0 或更高版本的所有设备都支持它。以下是简要概述:
有一个新的方便的 API 用于编译着色器程序,它还负责使它们“可分离”:
_vertexProgram = glCreateShaderProgramvEXT(GL_VERTEX_SHADER, 1, &source);
程序管道对象管理您的程序状态,让您混合和匹配已编译的着色器:
GLuint _ppo; glGenProgramPipelinesEXT(1, &_ppo); glBindProgramPipelineEXT(_ppo); glUseProgramStagesEXT(_ppo, GL_VERTEX_SHADER_BIT_EXT, _vertexProgram); glUseProgramStagesEXT(_ppo, GL_FRAGMENT_SHADER_BIT_EXT, _fragmentProgram);
混合和匹配着色器会使属性绑定(bind)变得很痛苦,因此您可以在着色器中指定(对于 varyings 也是如此):
#extension GL_EXT_separate_shader_objects : enable layout(location = 0) attribute vec4 position; layout(location = 1) attribute vec3 normal;
Uniforms 是为它们所属的着色器程序设置的:
glProgramUniformMatrix3fvEXT(_vertexProgram, u_normalMatrix, 1, 0, _normalMatrix.m);
关于ios - 构建基于 OpenGL ES 2.0 着色器的动态过滤器链的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18434510/