1 #include <GL/glew.h>
2 #include <GLFW/glfw3.h>
3 #include <iostream>
4
5 using namespace std;
6
7 const int numVAOs = 1;
8 GLuint renderingProgram;
9 GLuint vao[numVAOs];
10
11
12 GLuint createShaderProgram()
13 {
14 // 定义定点着色器源码
15 const char* vshaderSource =
16 // 声明着色器版本,与OpenGL版本同步
17 "#version 430 \n"
18 // 在顶点着色器,给 gl_Position指定out标签不是必需的,因为 gl_Position 是预定义的输出变量
19 //"out vec4 gl_Position; \n"
20 // main函数
21 "void main(void) \n"
22 // 用内置变量gl_Position在源码中硬编码一个顶点位置
23 "{ gl_Position = vec4(0.0, 0.0, 0.0, 1.0);}";
24
25 // 定义片段着色器源码
26 const char* fshaderSource =
27 // 声明着色器版本,与OpenGL版本同步
28 "#version 430 \n"
29 // out 标签表明color变量是输出变量
30 "out vec4 color; \n"
31 // main函数
32 "void main(void) \n"
33 // 设置颜色分量(rgba)
34 "{ color = vec4(0.0, 0.0, 1.0, 1.0);}";
35
36 // 创建顶点着色器
37 GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
38 // 创建片段着色器
39 GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
40 // 载入顶点着色器源码
41 glShaderSource(vShader, 1, &vshaderSource, nullptr);
42 // 载入片段着色器源码
43 glShaderSource(fShader, 1, &fshaderSource, nullptr);
44 // 编译顶点着色器
45 glCompileShader(vShader);
46 // 编译片段着色器
47 glCompileShader(fShader);
48 // 创建程序对象,OpenGL程序对象包含一系列编译过的着色器
49 GLuint vfProgram = glCreateProgram();
50 // 加入顶点着色器
51 glAttachShader(vfProgram, vShader);
52 // 加入片段着色器
53 glAttachShader(vfProgram, fShader);
54 // 链接程序
55 glLinkProgram(vfProgram);
56
57 return vfProgram;
58 }
59
60 void init(GLFWwindow* window) {
61 renderingProgram = createShaderProgram();
62 // 当准备将数据集发送给管线时,数据集是以缓冲区形式发送的。这些缓冲区最后都会被存入顶点数组对象
63 // 此案例我们在顶点着色器中硬编码一个点,因此不需要缓存区
64 // 即使如此,OpenGL依然需要创建一个VAO
65 glGenVertexArrays(numVAOs, vao);
66 glBindVertexArray(vao[0]);
67 }
68
69 void display(GLFWwindow* window, double currentTime)
70 {
71 // 指定颜色缓冲区清除后填充的值
72 glClearColor(1.0, 0.0, 0.0, 1.0);
73 // 用指定颜色清除(填充)颜色缓存区
74 glClear(GL_COLOR_BUFFER_BIT);
75 // 将含有两个已编译着色器的程序载入OpenGL管线阶段,并没有运行着色器
76 glUseProgram(renderingProgram);
77 // 设置绘制点的大小,便于观察
78 glPointSize(5);
79 // 启动管线处理过程,开始绘制
80 glDrawArrays(GL_POINTS, 0, 1);
81 }
82
83 int main(void)
84 {
85 // 如果glfw初始化失败则返回
86 if (!glfwInit()) { exit(EXIT_FAILURE); }
87 // 设置OpenGL程序的主版本号
88 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
89 // 设置OpenGL程序的副版本号
90 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
91 // 借助GLFW创建一个窗口
92 GLFWwindow* window = glfwCreateWindow(600, 600, "Graphics Program With OpenGL", nullptr, nullptr);
93 // 将GLFW创建的窗口与当前OpenGL的上下文关联起来
94 glfwMakeContextCurrent(window);
95 // 如果glew初始化失败则返回,glew负责调用OpenGL相关的函数
96 if (glewInit() != GLEW_OK) { exit(EXIT_FAILURE); }
97 // 交换间隔指示了直到交换缓冲区前需要等待多少帧,通常被理解为垂直同步。
98 // 默认情况下,交换间隔为0,意味着缓冲区交换会立即发生。
99 // 在一些快速的机器上,因为屏幕保持以典型的60 - 75次每秒的速度更新,许多帧会永远看不到,所以这会浪费许多CPU和GPU周期。
100 // 而且,因为缓冲区可能会在屏幕更新的中途被交换,导致画面撕裂。
101 // 因此,应用需要代表性地设置交换间隔为1。
102 glfwSwapInterval(1);
103
104 init(window);
105
106 // 当用户点击关闭窗口按钮时会返回true
107 while (!glfwWindowShouldClose(window))
108 {
109 display(window, glfwGetTime());
110 // GLFW默认使用了双缓冲技术。这意味着每个窗口会有两个渲染缓冲区,一个前置缓冲区和一个后置缓冲区。
111 // 前置缓冲区会在屏幕上显示而后置缓冲区是你渲染的目标。
112 // 当整个帧已经渲染完毕时,两个缓冲区需要进行交换,所以后置缓冲区会变成前置缓冲区,反之亦然。
113 glfwSwapBuffers(window);
114 // 处理窗口相关事件
115 glfwPollEvents();
116 }
117 // 销毁窗口
118 glfwDestroyWindow(window);
119 // 终止运行
120 glfwTerminate();
121
122 exit(EXIT_SUCCESS);
123 }