#include <iostream> // GLEW #define GLEW_STATIC #include <GL/glew.h> // GLFW #include <GLFW/glfw3.h> #pragma comment(lib,"opengl32.lib") #pragma comment(lib,"glu32.lib") using namespace std; // 窗口大小 const GLuint WIDTH = 800, HEIGHT = 600; // 着色器 GLSL const GLchar* vertexShaderSource = "#version 330 core\n" "layout (location = 0) in vec3 position;\n" "void main()\n" "{\n" "gl_Position = vec4(position.x, position.y, position.z, 1.0);\n" "}\0"; const GLchar* fragmentShaderSource0 = "#version 330 core\n" "out vec4 color;\n" "void main()\n" "{\n" "color = vec4(0.5f, 0.2f, 1.0f, 1.0f);\n" "}\n\0"; const GLchar* fragmentShaderSource1 = "#version 330 core\n" "out vec4 color;\n" "void main()\n" "{\n" "color = vec4(1.0f, 0.8f, 0.0f, 1.0f);\n" "}\n\0"; int main(void) { // 初始化 GLFW glfwInit(); // glfwWindowHint() // 配置 GLFW 函數(設置的選項,選項的值) glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Mac OS 使用 // glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 創建一個窗口 GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "FirstTriangle", nullptr, nullptr); glfwMakeContextCurrent(window); // 初始化 GLEW glewExperimental = GL_TRUE; glewInit(); // 設置窗口大小 int width, height; glfwGetFramebufferSize(window, &width, &height); glViewport(0, 0, width, height); // 配置着色器 // 創建一個着色器對象(GL_VERTEX_SHADER:頂點着色器) GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); // 把着色器源碼附加到着色器對象上,然后編譯它 glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); glCompileShader(vertexShader); // 檢測編譯時錯誤,輸出錯誤信息 GLint success; GLchar infoLog[512]; glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); if (!success){ glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl; } // 創建第1個着色器對象(GL_FRAGMENT_SHADER:片段着色器) GLuint fragmentShader0 = glCreateShader(GL_FRAGMENT_SHADER); // 着色器源碼附加及編譯 glShaderSource(fragmentShader0, 1, &fragmentShaderSource0, NULL); glCompileShader(fragmentShader0); // 檢測編譯時錯誤,輸出錯誤信息 glGetShaderiv(fragmentShader0, GL_COMPILE_STATUS, &success); if (!success){ glGetShaderInfoLog(fragmentShader0, 512, NULL, infoLog); std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; } // 創建第2個着色器對象(GL_FRAGMENT_SHADER:片段着色器) GLuint fragmentShader1 = glCreateShader(GL_FRAGMENT_SHADER); // 着色器源碼附加及編譯 glShaderSource(fragmentShader1, 1, &fragmentShaderSource1, NULL); glCompileShader(fragmentShader1); // 檢測編譯時錯誤,輸出錯誤信息 glGetShaderiv(fragmentShader1, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(fragmentShader1, 512, NULL, infoLog); std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl; } // 創建 2個着色器程序對象 GLuint shaderProgram0 = glCreateProgram(); GLuint shaderProgram1 = glCreateProgram(); // 鏈接着色器程序 glAttachShader(shaderProgram0, vertexShader); glAttachShader(shaderProgram1, vertexShader); glAttachShader(shaderProgram0, fragmentShader0); glAttachShader(shaderProgram1, fragmentShader1); glLinkProgram(shaderProgram0); glLinkProgram(shaderProgram1); // 激活對象 glUseProgram(shaderProgram0); // 檢查錯誤,輸出日志 glGetProgramiv(shaderProgram0, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shaderProgram0, 512, NULL, infoLog); std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; } glUseProgram(shaderProgram1); glGetProgramiv(shaderProgram1, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(shaderProgram1, 512, NULL, infoLog); std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; } // 激活后需要刪除着色器對象 glDeleteShader(vertexShader); glDeleteShader(fragmentShader0); glDeleteShader(fragmentShader1); // 輸入頂點數據(這是一個平面的三角形,z 坐標表示深度) //GLfloat vertices[] = { // -0.5f, -0.5f, 0.0f, // 0.5f, -0.5f, 0.0f, // 0.0f, 0.5f, 0.0f, }; // 輸入頂點數據(這是 2個平面的三角形) GLfloat vertices0[] = { -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -0.3f, 0.3f, 0.0f, }; GLfloat vertices1[] = { 0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.3f, 0.3f, 0.0f, }; // 生成 2個 VBO 對象 GLuint VBOs[2]; glGenBuffers(2, VBOs); // 創建 2個 VAO GLuint VAOs[2]; glGenVertexArrays(2, VAOs); // 把新創建的緩沖綁定到 GL_ARRAY_BUFFER 目標上 glBindVertexArray(VAOs[0]); glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]); // 把之前定義的頂點數據復制到緩沖的內存中(靜態圖形方式) // glBufferData() // 復制數據到當前綁定緩沖(緩沖類型,數據大小,數據,顯存數據的管理方式) glBufferData(GL_ARRAY_BUFFER, sizeof(vertices0), vertices0, GL_STATIC_DRAW); // glVertexAttribPointer() // 解析頂點數據(1.頂點屬性[對應前面的 layout (location = 0)],2.頂點屬性的大小[3分量向量], // 3.數據類型[浮點數],4.是否標准化為(-1,1)范圍內,5.單位步長,6.從起始位置的偏移量) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); // 第2個三角形 glBindVertexArray(VAOs[1]); glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), vertices1, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); // 解綁 glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); // 創建游戲循環 while (!glfwWindowShouldClose(window)) { // 事件處理 glfwPollEvents(); // 指定背景色(深藍色) glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); // 使用着色器程序, glDrawArrays():繪制圖元函數 glUseProgram(shaderProgram0); glBindVertexArray(VAOs[0]); //glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3); // 第2個三角形 glUseProgram(shaderProgram1); glBindVertexArray(VAOs[1]); glDrawArrays(GL_TRIANGLES, 0, 3); glBindVertexArray(0); // 交換緩沖 glfwSwapBuffers(window); } // 刪除 VAO 和 VBO,釋放空間 glDeleteVertexArrays(1, VAOs); glDeleteBuffers(1, VBOs); // 釋放 GLFW 內存 glfwTerminate(); return 0; }