1.GLSL语言
GLSL是着色器语言的一种,其他的着色器语言如HLSL,微软的3D框架DirectX等。着色器语言程序主要运行在GPU上。
GLSL是与OpenGL兼容的专用着色器语言,因此我们需要用GLSL编写着色器使用的程序代码。并将编写完的代码载入各个着色器阶段。其过程如下:
(1)编写GLSL程序代码(可以写进文件中,也可以硬编码在C++程序的字符串中。)
(2)使用C++获取GLSL程序代码。
(3)创建OpenGL着色器对象,并将GLSL程序代码加载进着色器对象。
(4)用OpenGL命令编译并链接着色器对象,并将其安装进GPU。
实践中,至少要顶点着色器和片段着色器阶段的GLSL代码,而曲面细分着色器和几何着色器阶段是可选的。
2.图元
OpenGL只允许绘制三类图形:点、线、三角形。它们叫做图元。即便是复杂的3D模型通常也是由许多三角形构成的。
图元由顶点组成。例如三角形有三个顶点。
顶点的来源可以是任意的,从文件中读取、硬编码在C++程序中或者直接在GLSL代码中。加载的顶点会被载入管线,经由着色器处理,最终变成屏幕上的各种形状。
Gl通过【glDrawArrays(GLenum mode,Glint first,Glsizei count)】方法绘制图元,其中mode是图元类型,first是从那个顶点开始绘制(通常是顶点0)。当调用该方法时,管线中的着色器(顶点着色器开始)开始执行。
3.着色器
顶点着色器:即处理顶点的着色器,所有顶点被载入管线后都会经由顶点着色器(即会对每个顶点执行一次(通常时并行的)),处理后载入管线的下一步。通过顶点着色器可以改变绘制内容的形状,包括形状大小、位置、角度、投影等等。
片段着色器:片段着色器负责处理绘制内容的颜色,所有顶点光栅化后经由片段着色器都会被赋值颜色,并且也会被插值处理。
代码示例:
1 #include <GL\glew.h> 2 #include <GLFW\glFW3.h> 3 4 #define numVAOs 1 5 6 GLuint renderingProgram; 7 GLuint vao[numVAOs]; //定义voa 8 //创建着色器程序 9 GLuint createShaderProgram() {
//GLSL程序代码 10 const char *vshaderSource = 11 "#version 430 \n" 12 "void main(void) \n" 13 "{ gl_Position = vec4(0.0, 0.0, 0.0, 1.0); }"; 14 //GLSL程序代码 15 const char *fshaderSource = 16 "#version 430 \n" 17 "out vec4 color; \n" 18 "void main(void) \n" 19 "{ color = vec4(0.0, 0.0, 1.0, 1.0); }"; 20 21 GLuint vShader = glCreateShader(GL_VERTEX_SHADER); //创建顶点着色器对象,返回对象ID 22 GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER); //创建片段着色器对象,返回对象ID 23 24 glShaderSource(vShader, 1, &vshaderSource, NULL); //将GLSL代码载入空着色器对象 25 glShaderSource(fShader, 1, &fshaderSource, NULL); //同上 26 glCompileShader(vShader); //编译着色器 27 glCompileShader(fShader); //同上 28 29 GLuint vfProgram = glCreateProgram(); //创建OpenGL程序对象,它包含一系列编译过的着色器对象。 30 glAttachShader(vfProgram, vShader); //将着色器对象加入程序对象 31 glAttachShader(vfProgram, fShader); //同上 32 glLinkProgram(vfProgram); //请求GLSL编译器确保新加入着色器对象的兼容性 33 //返回程序对象ID 34 return vfProgram; 35 } 36 37 int main(void) { 38 //初始化glfw库 39 if (!glfwInit()) 40 { 41 exit(EXIT_FAILURE); 42 } 43 //设置gl主版本号 44 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); 45 //设置gl次版本号,与主版本号一起指定了机器必须与opengl4.3版本兼容 46 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); 47 //创建glfw窗口,大小1280x640像素,窗口标题(window1) 48 GLFWwindow* window = glfwCreateWindow(1280,640,"window1", NULL, NULL); 49 //通知GLFW将我们窗口的上下文设置为当前opengl线程的主上下文 50 glfwMakeContextCurrent(window); 51 //初始化glew库 52 if (glewInit() != GLEW_OK) 53 { 54 exit(EXIT_FAILURE); 55 } 56 //设置缓冲区交换间隔(帧)。 默认情况下,交换间隔为0,但因缓冲区 57 //有可能在屏幕更新的中间交换,出现屏幕撕裂的情况。 58 //所以,可以将该间隔设为1,即每帧更新一次。 它可以设置为更高的 59 //值,但这可能导致输入延迟。 60 glfwSwapInterval(1); 61 62 init(window); 63 //检查GLFW是否被要求退出 64 while (!glfwWindowShouldClose(window)) { 65 display(window, glfwGetTime()); //glfwGetTime:获取glfw初始化后经过的时间 66 //交换缓冲区 67 glfwSwapBuffers(window); 68 //glfwPollEvents函数检查有没有触发什么事件(比如键盘输入、鼠标移动等)、更新窗口状态,并调用对应的回调函数(可以通过回调方法手动设置)。 69 glfwPollEvents(); 70 } 71 //glfw销毁窗口 72 glfwDestroyWindow(window); 73 //glfw终止运行 74 glfwTerminate(); 75 exit(EXIT_SUCCESS); 76 } 77 78 void init(GLFWwindow* window) { 79 renderingProgram = createShaderProgram(); //创建OpenGL程序对象,它包含一系列编译过的着色器对象 80 glGenVertexArrays(numVAOs, vao); //创建Vao 81 glBindVertexArray(vao[0]);//激活VAO 82 83 } 84 85 void display(GLFWwindow* window, double currentTime) { 86 glUseProgram(renderingProgram); //将OpenGL程序(包含我们编译进去的两个着色器对象)载入管线阶段(在GPU上);这一步并没有运行着色器,只是将着色器加载进硬件 87 glDrawArrays(GL_POINTS, 0, 1);//启动管线,描绘内容,图元是点。即描画一个点。 88 }
4.着色器代码解析:
顶点着色器:
#version 430 //指明GL版本:4.3
void main(void) //着色器是一个程序,与C++类似,也是从main函数开始
gl_Position//这是一个预定义的输出变量。用来设置顶点。并发送至下一个管线。
vec4//四元组,这里用来存储x,y,z,和齐次坐标值。
片段着色器:
out vec4 color; //指定一个输出变量,类型为四元组,名称是color。输出变量会自动输出到管线的下一阶段。
VAO:
vao是用来管理缓冲区的,所有的缓冲区都会被存入VAO。即便不使用任何缓冲区,OpenGl仍然需要创建至少一个VAO。