C / C ++中的OpenGL着色器的简单框架
我只想在平面图像上尝试一些着色器。 结果写了一个C程序,它只是把一张图片作为纹理应用,让我们说一个高斯模糊,作为一个片段着色器并不是那么容易:你必须初始化OpenGL,就像100行代码,然后了解GLBuffers等。另外与窗口系统的沟通还必须使用另一个框架GLUT。
原来,Nvidia的Fxcomposer php很喜欢使用着色器。但我仍然想要一个简单的C或C ++程序,它只是将给定的片段着色器应用于图像并显示结果。 有没有人有一个例子或有框架?
首先,我会避免使用过剩 – 这是错误的,大约十年没有更新,它的devise不适合大多数人现在想要的(例如,虽然你可以用它来animation,它的主要目的是产生一个静态显示)。 在前面的回答中,我指出了一些替代scheme。
这(大部分)会留下代码来编译,链接和使用着色器。 我写了一个小的类,我觉得这个目的很方便:
class shader_prog { GLuint vertex_shader, fragment_shader, prog; template <int N> GLuint compile(GLuint type, char const *(&source)[N]) { GLuint shader = glCreateShader(type); glShaderSource(shader, N, source, NULL); glCompileShader(shader); GLint compiled; glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); if (!compiled) { GLint length; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); std::string log(length, ' '); glGetShaderInfoLog(shader, length, &length, &log[0]); throw std::logic_error(log); return false; } return shader; } public: template <int N, int M> shader_prog(GLchar const *(&v_source)[N], GLchar const *(&f_source)[M]) { vertex_shader = compile(GL_VERTEX_SHADER, v_source); fragment_shader = compile(GL_FRAGMENT_SHADER, f_source); prog = glCreateProgram(); glAttachShader(prog, vertex_shader); glAttachShader(prog, fragment_shader); glLinkProgram(prog); } operator GLuint() { return prog; } void operator()() { glUseProgram(prog); } ~shader_prog() { glDeleteProgram(prog); glDeleteShader(vertex_shader); glDeleteShader(fragment_shader); } };
对于一个简单的演示,一些“传递”着色器(只是模拟固定function的pipe道):
const GLchar *vertex_shader[] = { "void main(void) {\n", " gl_Position = ftransform();\n", " gl_FrontColor = gl_Color;\n", "}" }; const GLchar *color_shader[] = { "void main() {\n", " gl_FragColor = gl_Color;\n", "}" };
你会用什么东西:
void draw() { // compile and link the specified shaders: static shader_prog prog(vertex_shader, color_shader); // Use the compiled shaders: prog(); // Draw something: glBegin(GL_TRIANGLES); glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(-1.0f, 0.0f, -1.0f); glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(1.0f, 0.0f, -1.0f); glColor3f(1.0f, 0.0f, 0.0f); glVertex3d(0.0, -1.0, -1.0); glEnd(); }
例如,如果要在绘制场景的过程中使用多个不同的片段着色器,则只需为每个场景定义一个静态对象,然后执行prog1();
, prog2();
等等,只是在绘制每个着色器的阴影对象之前。 例如,
void draw() { static shader_prog wall_shader("wall_vertex", "wall_frag"); static shader_prog skin_shader("skin_vertex", "skin_frag"); wall_shader(); draw_walls(); skin_shader(); draw_skin(); }
编辑:正如@rotoglup相当正确地指出,这个使用static
variables延迟破坏,直到OpenGL上下文已经被销毁,所以当析构函数试图使用glDeleteProgram
/ glDeleteShader
,结果是不可预知的(最好)。
虽然在演示程序中这可能是可以理解的,但在实际使用中,这绝对是不可取的。 同时,每次input使用它们的函数时,通常都不想重新编译着色器。
为了避免这两个问题,通常需要将着色器对象创build为类实例的成员,该类的实例的生命周期与任何将要影响的生命周期相关联:
class some_character_type { shader_prog skin_shader; public: // ... };
当你创build一个该types的angular色时,它将编译/链接着色器程序一次,并且当你摧毁该angular色时将其销毁。
当然,在一些情况下,这也不是完全合意的。 举例来说,考虑古代“杀死大量目标”游戏,如Galaga或蜈蚣的3D版本。 对于这样的游戏,你可以相对快速地创build和销毁大量基本相同的目标。 如果给定大量基本相同的目标,则可能需要使用像shared_ptr<shader_prog>
类的东西来创build在特定目标types的所有实例之间共享的着色器的单个实例。 考虑到你多次使用相同的目标types,你甚至可能要比这更进一步,所以你在整个游戏中保持着相同的着色器,而不仅仅是当一个特定types的目标被显示时。
无论如何,我们在这里有点偏离。 关键是编译和链接着色器是一个相当昂贵的过程,所以你通常要pipe理它们的生命周期,以避免创build和销毁它们往往比真正需要更多的时间(虽然这并不是说在所有的创build在游戏的开始,只有在最后销毁它们)。
大约一年半前,我也处于类似的位置。 我很快find了一个简单的教程和使用GLSL的源代码..但是我必须得到GLUT和GLEW的工作,而且我想我至less编译了其中的一个。 由于我使用的是Windows(而且Windows是一个非标准的特殊情况,很less被开放项目全面处理),它也涉及到一个荒谬的过程,我期望手动复制和粘贴DLL和头文件到某些常见的位置。 这总是一种痛苦,我已经失去了我生活中的很大一部分,但是我按照指示走过了这个过程,最终结果如常。
无论如何,使用GLSL的最方便的着色器例子,我现在可以find的是这一个 – http://www.lighthouse3d.com/opengl/glsl/index.php?minimal
它并没有像你所希望的那样专门修改纹理。但是根据我的经验,一旦你得到了像这样编译和运行的代码,体验将会更加愉快,你将很快地取得进展,并且能够从其他教程中拼凑出来如有必要。 我可以说,一旦我运行了一个例子,我就用同样的框架来快速解决家庭和工作中的许多问题。
我很抱歉说它确实使用了GLUT和GLEW。 如果你对这个问题得到更好的回答,我也会成为任何站点提供代码的即时粉丝。 祝你好运。
本教程可能是有用的(注意,它包含除了旧的Cg东西以外的GLSL材料)。
请注意,我认为编写着色器来实现非graphics的,GPGPUtypes的东西是最近已经过时的方法。 OpenCL或CUDA显然是未来的方向。
虽然这不是你的目标,但你可能会从Noel Llopis的OpenGL ES 2.0着色器示例中获得一些东西: http : //www.mobileorchard.com/getting-started-with-opengl-es-20-on-the-iphone-3gs/