学习自:
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 }