学习自:

https://learnopengl-cn.github.io/01%20Getting%20started/05%20Shaders/#_4

  1 #include <glad/glad.h>
  2 #include <GLFW/glfw3.h>
  3 
  4 #include <iostream>
  5 #include <cmath>
  6 
  7 void framebuffer_size_callback(GLFWwindow* window, int width, int height);
  8 void processInput(GLFWwindow *window);
  9 
 10 // 设置窗体的宽度和高度
 11 const unsigned int SCR_WIDTH = 800;
 12 const unsigned int SCR_HEIGHT = 600;
 13 
 14 const char *vertexShaderSource = "#version 330 core\n"
 15 "layout (location = 0) in vec3 aPos;\n"
 16 "void main()\n"
 17 "{\n"
 18 "   gl_Position = vec4(aPos, 1.0);\n"
 19 "}\0";
 20 
 21 const char *fragmentShaderSource = "#version 330 core\n"
 22 "out vec4 FragColor;\n"
 23 "uniform vec4 ourColor;\n"
 24 "void main()\n"
 25 "{\n"
 26 "   FragColor = ourColor;\n"
 27 "}\n\0";
 28 
 29 int main()
 30 {
 31     // 初始化glfw
 32     glfwInit();
 33     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
 34     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
 35     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
 36 
 37     // 条件编译语句,如果是苹果系统?
 38 #ifdef __APPLE__
 39     glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // uncomment this statement to fix compilation on OS X
 40 #endif
 41 
 42     // 创建glfw窗体
 43     GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
 44     if (window == NULL)
 45     {
 46         std::cout << "Failed to create GLFW window" << std::endl;
 47         glfwTerminate();
 48         return -1;
 49     }
 50     glfwMakeContextCurrent(window);
 51     glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
 52 
 53     // glad: load all OpenGL function pointers
 54     // ---------------------------------------
 55     if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
 56     {
 57         std::cout << "Failed to initialize GLAD" << std::endl;
 58         return -1;
 59     }
 60 
 61     // 创建并编译着色器
 62     // vertex shader
 63     int vertexShader = glCreateShader(GL_VERTEX_SHADER);
 64     //glShaderSource函数把要编译的着色器对象作为第一个参数。
 65     //第二参数指定了传递的源码字符串数量,这里只有一个。
 66     //第三个参数是顶点着色器真正的源码。
 67     //第四个参数我们先设置为NULL。
 68     glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
 69     glCompileShader(vertexShader);
 70     // 错误检测
 71     int success;//表示是否编译成功
 72     char infoLog[512];//存储错误信息
 73     glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
 74     if (!success)
 75     {
 76         glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
 77         std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
 78     }
 79     // 片段着色器
 80     int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
 81     glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
 82     glCompileShader(fragmentShader);
 83     // 错误检测
 84     glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
 85     if (!success)
 86     {
 87         glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
 88         std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
 89     }
 90     // 将着色器链接为一个着色器对象
 91     int shaderProgram = glCreateProgram();
 92     glAttachShader(shaderProgram, vertexShader);
 93     glAttachShader(shaderProgram, fragmentShader);
 94     glLinkProgram(shaderProgram);
 95     // 错误检测
 96     glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
 97     if (!success) {
 98         glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
 99         std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
100     }
101     //在把着色器对象链接到程序对象以后,记得删除着色器对象,我们不再需要它们了:
102     glDeleteShader(vertexShader);
103     glDeleteShader(fragmentShader);
104 
105     // 设置顶点
106     float vertices[] = {
107          0.5f, -0.5f, 0.0f,  // bottom right
108         -0.5f, -0.5f, 0.0f,  // bottom left
109          0.0f,  0.5f, 0.0f   // top 
110     };
111     //创建一个VAO——顶点数组对象(Vertex Array Object, VAO)
112     //        VAO可以像顶点缓冲对象那样被绑定,任何随后的顶点属性调用都会储存在这个VAO中。
113     //创建VBO——顶点缓冲对象:Vertex Buffer Object,VBO
114     //        它会在GPU内存(通常被称为显存)中储存大量顶点。
115     //        使用这些缓冲对象的好处是我们可以一次性的发送一大批数据到显卡上,而不是每个顶点发送一次。
116     unsigned int VBO, VAO;
117     glGenVertexArrays(1, &VAO);
118     glGenBuffers(1, &VBO);
119     // 1.绑定VOA
120     glBindVertexArray(VAO);
121     // 2.把顶点数组复制到缓冲中供OpenGL使用
122     glBindBuffer(GL_ARRAY_BUFFER, VBO);
123     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
124 
125     /*
126     GL_STATIC_DRAW :数据不会或几乎不会改变。
127     GL_DYNAMIC_DRAW:数据会被改变很多。
128     GL_STREAM_DRAW :数据每次绘制时都会改变。
129     */
130 
131     // 3.设置顶点属性指针
132     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
133     glEnableVertexAttribArray(0);
134 
135     glBindVertexArray(VAO);
136 
137 
138     // 循环渲染
139     // -----------
140     while (!glfwWindowShouldClose(window))
141     {
142         // 输入
143         processInput(window);
144 
145         // 渲染
146         // 清楚颜色缓冲
147         glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
148         glClear(GL_COLOR_BUFFER_BIT);
149 
150         // 记得激活着色器
151         glUseProgram(shaderProgram);
152 
153         // 更新uniform,然后每个渲染迭代都更新这个uniform:
154         /*
155         首先我们通过glfwGetTime()获取运行的秒数。
156         然后我们使用sin函数让颜色在0.0到1.0之间改变,
157         最后将结果储存到greenValue里。
158         */
159         float timeValue = glfwGetTime();
160         float greenValue = sin(timeValue) / 2.0f + 0.5f;
161         /*
162         用glGetUniformLocation查询uniform ourColor的位置值。
163         如果glGetUniformLocation返回-1就代表没有找到这个位置值。
164 
165         注意,查询uniform地址不要求你之前使用过着色器程序,
166         但是更新一个uniform之前你必须先使用程序(调用glUseProgram),
167         因为它是在当前激活的着色器程序中设置uniform的。
168         */
169         int vertexColorLocation = glGetUniformLocation(shaderProgram, "ourColor");
170         //最后,我们可以通过glUniform4f函数设置uniform值。
171         glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
172 
173         // 绘制三角形
174         glDrawArrays(GL_TRIANGLES, 0, 3);
175 
176         // 交换缓冲并查询IO事件
177         glfwSwapBuffers(window);
178         glfwPollEvents();
179     }
180 
181     // 取消分配的空间
182     glDeleteVertexArrays(1, &VAO);
183     glDeleteBuffers(1, &VBO);
184 
185     // 终止,清除所有先前分配的GLFW资源。
186     glfwTerminate();
187     return 0;
188 }
189 
190 // glfw:点击esc退出,可是删掉这一块前面的东西还会报错,还是留着吧
191 void processInput(GLFWwindow *window)
192 {
193     if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
194         glfwSetWindowShouldClose(window, true);
195 }
196 
197 // 每当窗口大小发生变化(通过OS或用户调整大小)时,都会执行此回调函数
198 void framebuffer_size_callback(GLFWwindow* window, int width, int height)
199 {
200     //确保视口与新窗口尺寸匹配; 请注意宽度和
201     //高度将远远大于视网膜显示器上指定的高度。
202     glViewport(0, 0, width, height);
203 }