今天来谈一谈两个基本的着色器VERTEX SHADER(顶点着色器) 和FRAGMENT SHADER(片段着色器)以及如何使用。在此之前,需要先说明的是,每一个着色器都有输入与输出,上一着色器的输出是往往是作为下一着色器的输入的。(意味着,每一个着色器的输入和输出形式都是固定的)。
编写顶点着色器
编写一个基础的顶点着色器(设置顶点的属性),我们需要:
-
版本申明
-
为输入变量创造类型为vec3的aPos容器并指定其位置值(location=15)(输入)1
-
设置顶点着色器的输出内容,其输出为vec4类型(输出)
"#version 330 core \n "
"layout(location = 15) in vec3 aPos; \n "
"void main() {\n "
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);} \n ";
编译着色器
当声明完一个顶点着色器A后,我们需要做的就是编译着色器。着色器的编译都是一样的,只是在于着色器的类型不一样(顶点着色器,片段着色器等),以顶点着色器为例,着色器基本编译如下:
1.使用glCreateShader()创建一个类型为顶点着色器(GL_VERTEX_SHADER)的着色器B,glCreateShader()会返回该着色器的ID值2
unsigned int vertexShader;
vertexShader=glCreateShader(GL_VERTEX_SHADER);
2.将我们编写的顶点着色器附加到我们创建的着色器上,这里使用的是glShaderSource();
glShaderSource(创建的B着色器,A着色器的字符串数量,编写的A着色器的地址(真正的源码),)
glShaderSource(vertexShader,1,&vertexShaderSource,NULL);
3.最终,我们才要真正的编译着色器了,使用的是glCompileShader();
glCompileShader(vertexShader);
编写片段着色器
编写一个基础的片段着色器(设置栅格的颜色),我们需要:
-
版本申明
-
设置类型为vec4的片段着色器的输出(输出)
-
设置片段着色器的输出的内容
const char* fragmentShaderSource =
"#version 330 core \n "
"out vec4 FragColor; \n "
"void main() {\n "
" FragColor = vec4(0.27f, 0.54f, 0.58f, 1.0f);} \n ";
着色器的编译同上,只是类型改为了片段着色器(GL_FRAGMENT_SHADER)。
着色器程序
在对着色器进行了编写与编译后,我们需要将这些着色器集成在一起成为一个着色器程序对象。
着色器对象就像一个模板,我们对不同的点集合使用某个已经定好了的着色器模板。比如精简几何风,欧式风等
创建着色器程序对象的基本流程如下:
1.创建一个着色器对象,使用的是glCreateProgramme()函数,该函数返回的也是一个ID值。
unsigned int shaderProgramme;
shaderProgramme = glCreateProgram();
2…将我们编写的着色器附加到我们创建的着色器对象上,使用的函数是glAttachShader(着色器程序,着色器);
然后将着色器对象与程序使用glLinkProgram();进行连接,成为一个着色器程序对象。
glAttachShader(shaderProgramme,vertexShader);
glAttachShader(shaderProgramme,fragmentShader);
glLinkProgram(shaderProgramme);
3.通过glUseProgram();使用创建的着色器程序对象(在相应的OpenGL窗口中)
glUseProgram(shaderProgramme);
4.用完记得使用glDeleteShader();删除各个着色器。
总结
通过以上的简单使用,不难发现,整个着色器的使用都是类似于
- 自行创建一个着色器,
- 将XXXX附加到创建的着色器上
- 链接/编译
这样的一个过程。首先我们需要理解OpenGL是通过设定上下文(Context)进行的变换,基于这点,着色器的使用可以理解为,我们是通过设置属性来完成我们想要的界面显示,而这些属性的具体内容是通过另外一套(GLSL)构建的。