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。