你好贤重,三角形(頂點(diǎn)輸入、頂點(diǎn)著色器清焕、編譯著色器并蝗、片段著色器、鏈接頂點(diǎn)屬性秸妥、VBO滚停、VAO、EBO)

  •  [https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/#_12](https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/#_12)
    
    •   /*
          頂點(diǎn)數(shù)組對(duì)象:Vertex Array Object粥惧,VAO
          頂點(diǎn)緩沖對(duì)象:Vertex Buffer Object键畴,VBO
          索引緩沖對(duì)象:Element Buffer Object,EBO或Index Buffer Object突雪,IBO
      */
      
      #include "pch.h"
      //GLEW
      #include <iostream>
      
      #define GLEW_STATIC
      #include <GL/glew.h>
      #include <GLFW/glfw3.h>
      
      #include "SOIL2/SOIL2.h"
      #include "glm/glm.hpp"
      #include "glm/gtc/type_ptr.hpp"
      #include "Shader.h"
      
      void processInput(GLFWwindow *window);
      
      //頂點(diǎn)著色器源碼
      //頂點(diǎn)著色器主要的目的是把3D坐標(biāo)轉(zhuǎn)為另一種3D坐標(biāo)(后面會(huì)解釋?zhuān)?//同時(shí)頂點(diǎn)著色器允許我們對(duì)頂點(diǎn)屬性進(jìn)行一些基本處理起惕。
      const char *vertexShaderSource = "#version 330 core\n"
          "layout (location = 0) in vec3 aPos;\n"
          "void main()\n"
          "{\n"
          "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
          "}\0";
      //片段著色器的主要目的是計(jì)算一個(gè)像素的最終顏色,這也是所有OpenGL高級(jí)效果產(chǎn)生的地方咏删。
      //通常惹想,片段著色器包含3D場(chǎng)景的數(shù)據(jù)(比如光照、陰影督函、光的顏色等等)嘀粱,這些數(shù)據(jù)可以被用來(lái)計(jì)算最終像素的顏色。
      //對(duì)象著色器源碼
      const char *fragmentShaderSource = "#version 330 core\n"
          "out vec4 FragColor;\n"
          "void main()\n"
          "{\n"
          "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
          "}\n\0";
      
      int main() {
      
          //初始化GLFW
          glfwInit();
          //使用flfwWindowHint函數(shù)來(lái)配置GLFW
          /*
          glfwWindowHint函數(shù)的第一個(gè)參數(shù)代表選項(xiàng)的名稱侨核,
          我們可以從很多以GLFW_開(kāi)頭的枚舉值中選擇草穆;
          第二個(gè)參數(shù)接受一個(gè)整型,
          用來(lái)設(shè)置這個(gè)選項(xiàng)的值
          */
          glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
          glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
          glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
      
          //glfwCreateWindow函數(shù)需要窗口的寬和高作為它的前兩個(gè)參數(shù)
          //第三個(gè)參數(shù)表示這個(gè)窗口的名稱
          GLFWwindow* window = glfwCreateWindow(800, 600, "B7040312", NULL, NULL);
          if (window == NULL)
          {
              std::cout << "Failed to create GLFW window" << std::endl;
              glfwTerminate();
              return -1;
          }
          //創(chuàng)建完窗口我們就可以通知GLFW將我們窗口的上下文設(shè)置為當(dāng)前線程的主上下文了
          glfwMakeContextCurrent(window);
      
          //GLEW是用來(lái)管理OpenGL的函數(shù)指針的搓译,所以在調(diào)用任何OpenGL的函數(shù)之前我們需要初始化GLEW
          //glewExperimental所做的是即使驅(qū)動(dòng)程序的擴(kuò)展程序字符串中不存在擴(kuò)展程序悲柱,也允許加載擴(kuò)展程序入口點(diǎn)。
          glewExperimental = GL_TRUE;
          if (glewInit() != GLEW_OK)
          {
              std::cout << "Failed to initialize GLEW" << std::endl;
              return -1;
          }
      
          /*
          開(kāi)始渲染之前還有一件重要的事情要做些己,我們必須告訴OpenGL渲染窗口的尺寸大小豌鸡,這樣OpenGL才只能知道怎樣相對(duì)于窗口大小顯示數(shù)據(jù)和坐標(biāo)嘿般。
          我們可以通過(guò)調(diào)用glViewport函數(shù)來(lái)設(shè)置窗口的維度(Dimension):
          */
      
          /*
          然而,當(dāng)用戶改變窗口的大小的時(shí)候涯冠,視口也應(yīng)該被調(diào)整炉奴。
          我們可以對(duì)窗口注冊(cè)一個(gè)回調(diào)函數(shù)(Callback Function),
          它會(huì)在每次窗口大小被調(diào)整的時(shí)候被調(diào)用
          */
          int width, height;
      
          glfwGetFramebufferSize(window, &width, &height);
          /*
          glViewport函數(shù)前兩個(gè)參數(shù)控制窗口左下角的位置蛇更。
          第三個(gè)和第四個(gè)參數(shù)控制渲染窗口的寬度和高度(像素)瞻赶,這里我們是直接從GLFW中獲取的。
          */
          glViewport(0, 0, width, height);
      
          //創(chuàng)建著色器對(duì)象 創(chuàng)建類(lèi)型 附加著色器源碼 編譯 
          // build and compile our shader program
          // ------------------------------------
          // vertex shader(頂點(diǎn)著色器)
          int vertexShader = glCreateShader(GL_VERTEX_SHADER);
          glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
          glCompileShader(vertexShader);
          // check for shader compile errors
          int success;
          char 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;
          }
          // fragment shader(片段著色器)
          int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
          glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
          glCompileShader(fragmentShader);
          // check for shader compile errors
          glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
          if (!success)
          {
              glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
              std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
          }
          // link shaders
          int shaderProgram = glCreateProgram();
          glAttachShader(shaderProgram, vertexShader);
          glAttachShader(shaderProgram, fragmentShader);
          glLinkProgram(shaderProgram);
          // check for linking errors
          glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
          if (!success) {
              glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
              std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
          }
          glDeleteShader(vertexShader);
          glDeleteShader(fragmentShader);
      
          /*
              由于我們希望渲染一個(gè)三角形派任,我們一共要指定三個(gè)頂點(diǎn)砸逊,每個(gè)頂點(diǎn)都有一個(gè)3D位置。
              我們會(huì)將它們以標(biāo)準(zhǔn)化設(shè)備坐標(biāo)的形式(OpenGL的可見(jiàn)區(qū)域)定義為一個(gè)float數(shù)組掌逛。
              由于OpenGL是在3D空間中工作的师逸,而我們渲染的是一個(gè)2D三角形,我們將它頂點(diǎn)的z坐標(biāo)設(shè)置為0.0豆混。
              這樣子的話三角形每一點(diǎn)的深度(Depth篓像,譯注2)都是一樣的,從而使它看上去像是2D的皿伺。
          */
          float vertices[] = {
              -0.5f, -0.5f, 0.0f, // left  
               0.5f, -0.5f, 0.0f, // right 
               0.0f,  0.5f, 0.0f  // top   
          };
          /*
              定義這樣的頂點(diǎn)數(shù)據(jù)以后员辩,我們會(huì)把它作為輸入發(fā)送給圖形渲染管線的第一個(gè)處理階段:頂點(diǎn)著色器。
              它會(huì)在GPU上創(chuàng)建內(nèi)存用于儲(chǔ)存我們的頂點(diǎn)數(shù)據(jù)心傀,還要配置OpenGL如何解釋這些內(nèi)存屈暗,并且指定其如何發(fā)送給顯卡拆讯。
              頂點(diǎn)著色器接著會(huì)處理我們?cè)趦?nèi)存中指定數(shù)量的頂點(diǎn)脂男。
      
              我們通過(guò)頂點(diǎn)緩沖對(duì)象(Vertex Buffer Objects, VBO)管理這個(gè)內(nèi)存,
              它會(huì)在GPU內(nèi)存(通常被稱為顯存)中儲(chǔ)存大量頂點(diǎn)种呐。
              使用這些緩沖對(duì)象的好處是我們可以一次性的發(fā)送一大批數(shù)據(jù)到顯卡上宰翅,而不是每個(gè)頂點(diǎn)發(fā)送一次。
              從CPU把數(shù)據(jù)發(fā)送到顯卡相對(duì)較慢爽室,所以只要可能我們都要嘗試盡量一次性發(fā)送盡可能多的數(shù)據(jù)汁讼。
              當(dāng)數(shù)據(jù)發(fā)送至顯卡的內(nèi)存中后,頂點(diǎn)著色器幾乎能立即訪問(wèn)頂點(diǎn)阔墩,這是個(gè)非澈偌埽快的過(guò)程。
          */
      
          //頂點(diǎn)緩沖對(duì)象 
          //頂點(diǎn)數(shù)組對(duì)象
          unsigned int VBO, VAO;
      
          //以使用glGenVertexArrays函數(shù)和一個(gè)緩沖ID生成一個(gè)VAO對(duì)象:
          glGenVertexArrays(1, &VAO);
      
          //VBO:
          //以使用glGenBuffers函數(shù)和一個(gè)緩沖ID生成一個(gè)VBO對(duì)象:
          //OpenGL有很多緩沖對(duì)象類(lèi)型啸箫,頂點(diǎn)緩沖對(duì)象的緩沖類(lèi)型是GL_ARRAY_BUFFER耸彪。
          //OpenGL允許我們同時(shí)綁定多個(gè)緩沖,只要它們是不同的緩沖類(lèi)型忘苛。
          //我們可以使用glBindBuffer函數(shù)把新創(chuàng)建的緩沖綁定到GL_ARRAY_BUFFER目標(biāo)上:
          //從這一刻起蝉娜,我們使用的任何(在GL_ARRAY_BUFFER目標(biāo)上的)緩沖調(diào)用
          //都會(huì)用來(lái)配置當(dāng)前綁定的緩沖(VBO)唱较。
          glGenBuffers(1, &VBO);
      
          //VAO:首先綁定頂點(diǎn)數(shù)組對(duì)象
          glBindVertexArray(VAO);
          glBindBuffer(GL_ARRAY_BUFFER, VBO);
      
          //VAO:然后把頂點(diǎn)數(shù)組復(fù)制到緩沖中供OpenGL使用
          //VBO:然后我們可以調(diào)用glBufferData函數(shù),它會(huì)把之前定義的頂點(diǎn)數(shù)據(jù)復(fù)制到緩沖的內(nèi)存中:
          glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
      
          //VAO:最后設(shè)置頂點(diǎn)屬性指針
          //對(duì)glVertexAttribPointer的調(diào)用將VBO注冊(cè)為頂點(diǎn)屬性的綁定頂點(diǎn)緩沖區(qū)對(duì)象召川,因此之后我們可以安全地解除綁定
          //鏈接頂點(diǎn)屬性
          //每個(gè)頂點(diǎn)屬性從一個(gè)VBO管理的內(nèi)存中獲得它的數(shù)據(jù)南缓,而具體是從哪個(gè)VBO(程序中可以有多個(gè)VBO)
          //獲取則是通過(guò)在調(diào)用glVertexAttribPointer時(shí)綁定到GL_ARRAY_BUFFER的VBO決定的。
          //由于在調(diào)用glVertexAttribPointer之前綁定的是先前定義的VBO對(duì)象荧呐,頂點(diǎn)屬性0現(xiàn)在會(huì)鏈接到它的頂點(diǎn)數(shù)據(jù)汉形。
          glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
          //我們現(xiàn)在應(yīng)該使用glEnableVertexAttribArray,以頂點(diǎn)屬性位置值作為參數(shù)倍阐,啟用頂點(diǎn)屬性获雕;頂點(diǎn)屬性默認(rèn)是禁用的
          glEnableVertexAttribArray(0);
      
          glBindBuffer(GL_ARRAY_BUFFER, 0);
          //之后您可以解除綁定VAO,這樣其他VAO調(diào)用就不會(huì)意外修改此VAO收捣,但這很少發(fā)生届案。 修改其他
          // VAO無(wú)論如何都需要調(diào)用glBindVertexArray,因此通常在不需要時(shí)罢艾,我們通常不會(huì)取消綁定VAO(也沒(méi)有VBO)楣颠。
          glBindVertexArray(0);
      
          /*
          一般當(dāng)你打算繪制多個(gè)物體時(shí),你首先要生成/配置所有的VAO(和必須的VBO及屬性指針)咐蚯,
          然后儲(chǔ)存它們供后面使用童漩。
          當(dāng)我們打算繪制物體的時(shí)候就拿出相應(yīng)的VAO,綁定它春锋,繪制完物體后矫膨,再解綁VAO。
          */
      
          /*
          我們希望程序在我們主動(dòng)關(guān)閉它之前不斷繪制圖像并能夠接受用戶輸入期奔。
          因此侧馅,我們需要在程序中添加一個(gè)while循環(huán),我們可以把它稱之為渲染循環(huán)(Render Loop)呐萌,
          它能在我們讓GLFW退出前一直保持運(yùn)行馁痴。
          下面幾行的代碼就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的渲染循環(huán):
          */
          /*
          glfwWindowShouldClose函數(shù)在我們每次循環(huán)的開(kāi)始前檢查一次GLFW是否被要求退出,
          如果是的話該函數(shù)返回true然后渲染循環(huán)便結(jié)束了肺孤,之后為我們就可以關(guān)閉應(yīng)用程序了罗晕。
          */
          while (!glfwWindowShouldClose(window))
          {
              // input
              // -----
              processInput(window);
      
              // render
              // ------
              //要把所有的渲染(Rendering)操作放到渲染循環(huán)中,
              //因?yàn)槲覀兿胱屵@些渲染指令在每次渲染循環(huán)迭代的時(shí)候都能被執(zhí)行赠堵。
              glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
              glClear(GL_COLOR_BUFFER_BIT);
      
              // draw our first triangle
              glUseProgram(shaderProgram);
              glBindVertexArray(VAO); //我們只有一個(gè)VAO小渊,因此不必每次都綁定它,但是我們這樣做是為了使事情更有條理
              //glDrawArrays函數(shù)茫叭,它使用當(dāng)前激活的著色器酬屉,之前定義的頂點(diǎn)屬性配置,和VBO的頂點(diǎn)數(shù)據(jù)(通過(guò)VAO間接綁定)來(lái)繪制圖元杂靶。
              glDrawArrays(GL_TRIANGLES, 0, 3);
      
              /*
              glfwSwapBuffers函數(shù)會(huì)交換顏色緩沖(它是一個(gè)儲(chǔ)存著GLFW窗口每一個(gè)像素顏色值的大緩沖)梆惯,
              它在這一迭代中被用來(lái)繪制酱鸭,并且將會(huì)作為輸出顯示在屏幕上。
              */
              /*
              glfwPollEvents函數(shù)檢查有沒(méi)有觸發(fā)什么事件(比如鍵盤(pán)輸入垛吗、鼠標(biāo)移動(dòng)等)凹髓、更新窗口狀態(tài),
              并調(diào)用對(duì)應(yīng)的回調(diào)函數(shù)(可以通過(guò)回調(diào)方法手動(dòng)設(shè)置)
              */
              glfwSwapBuffers(window);
              glfwPollEvents();
          }
      
          //delete
          glDeleteVertexArrays(1, &VAO);
          glDeleteBuffers(1, &VBO);
          /*
          當(dāng)渲染循環(huán)結(jié)束后我們需要正確釋放/刪除之前的分配的所有資源怯屉。
          我們可以在main函數(shù)的最后調(diào)用glfwTerminate函數(shù)來(lái)完成蔚舀。
          */
          glfwTerminate();
          return 0;
      }
      
      void processInput(GLFWwindow *window)
      {
          //檢測(cè)是否按下esc,按下則退出循環(huán)
          if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
              glfwSetWindowShouldClose(window, true);
      }
      
      

*效果

*
image.png
  • 用EBO畫(huà)長(zhǎng)方形
/*
    頂點(diǎn)數(shù)組對(duì)象:Vertex Array Object锨络,VAO
    頂點(diǎn)緩沖對(duì)象:Vertex Buffer Object赌躺,VBO
    索引緩沖對(duì)象:Element Buffer Object,EBO或Index Buffer Object羡儿,IBO
*/

#include "pch.h"
//GLEW
#include <iostream>

#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "SOIL2/SOIL2.h"
#include "glm/glm.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "Shader.h"




void processInput(GLFWwindow *window);

//頂點(diǎn)著色器源碼
//頂點(diǎn)著色器主要的目的是把3D坐標(biāo)轉(zhuǎn)為另一種3D坐標(biāo)(后面會(huì)解釋?zhuān)?//同時(shí)頂點(diǎn)著色器允許我們對(duì)頂點(diǎn)屬性進(jìn)行一些基本處理礼患。
const char *vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    "}\0";
//片段著色器的主要目的是計(jì)算一個(gè)像素的最終顏色,這也是所有OpenGL高級(jí)效果產(chǎn)生的地方掠归。
//通常缅叠,片段著色器包含3D場(chǎng)景的數(shù)據(jù)(比如光照、陰影虏冻、光的顏色等等)肤粱,這些數(shù)據(jù)可以被用來(lái)計(jì)算最終像素的顏色。
//對(duì)象著色器源碼
const char *fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n\0";



int main() {

    //初始化GLFW
    glfwInit();
    //使用flfwWindowHint函數(shù)來(lái)配置GLFW
    /*
    glfwWindowHint函數(shù)的第一個(gè)參數(shù)代表選項(xiàng)的名稱厨相,
    我們可以從很多以GLFW_開(kāi)頭的枚舉值中選擇领曼;
    第二個(gè)參數(shù)接受一個(gè)整型,
    用來(lái)設(shè)置這個(gè)選項(xiàng)的值
    */
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    

    //glfwCreateWindow函數(shù)需要窗口的寬和高作為它的前兩個(gè)參數(shù)
    //第三個(gè)參數(shù)表示這個(gè)窗口的名稱
    GLFWwindow* window = glfwCreateWindow(800, 600, "B7040312", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    //創(chuàng)建完窗口我們就可以通知GLFW將我們窗口的上下文設(shè)置為當(dāng)前線程的主上下文了
    glfwMakeContextCurrent(window);

    //GLEW是用來(lái)管理OpenGL的函數(shù)指針的蛮穿,所以在調(diào)用任何OpenGL的函數(shù)之前我們需要初始化GLEW
    //glewExperimental所做的是即使驅(qū)動(dòng)程序的擴(kuò)展程序字符串中不存在擴(kuò)展程序庶骄,也允許加載擴(kuò)展程序入口點(diǎn)。
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK)
    {
        std::cout << "Failed to initialize GLEW" << std::endl;
        return -1;
    }





    /*
    開(kāi)始渲染之前還有一件重要的事情要做绪撵,我們必須告訴OpenGL渲染窗口的尺寸大小瓢姻,這樣OpenGL才只能知道怎樣相對(duì)于窗口大小顯示數(shù)據(jù)和坐標(biāo)祝蝠。
    我們可以通過(guò)調(diào)用glViewport函數(shù)來(lái)設(shè)置窗口的維度(Dimension):
    */

    /*
    然而音诈,當(dāng)用戶改變窗口的大小的時(shí)候,視口也應(yīng)該被調(diào)整绎狭。
    我們可以對(duì)窗口注冊(cè)一個(gè)回調(diào)函數(shù)(Callback Function)细溅,
    它會(huì)在每次窗口大小被調(diào)整的時(shí)候被調(diào)用
    */
    int width, height;
    
    glfwGetFramebufferSize(window, &width, &height);
    /*
    glViewport函數(shù)前兩個(gè)參數(shù)控制窗口左下角的位置。
    第三個(gè)和第四個(gè)參數(shù)控制渲染窗口的寬度和高度(像素)儡嘶,這里我們是直接從GLFW中獲取的喇聊。
    */
    glViewport(0, 0, width, height);






    //創(chuàng)建著色器對(duì)象 創(chuàng)建類(lèi)型 附加著色器源碼 編譯 
    // build and compile our shader program
    // ------------------------------------
    // vertex shader(頂點(diǎn)著色器)
    int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    // check for shader compile errors
    int success;
    char 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;
    }
    // fragment shader(片段著色器)
    int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    // check for shader compile errors
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }
    // link shaders
    int shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    // check for linking errors
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    /*
        由于我們希望渲染一個(gè)三角形,我們一共要指定三個(gè)頂點(diǎn)蹦狂,每個(gè)頂點(diǎn)都有一個(gè)3D位置誓篱。
        我們會(huì)將它們以標(biāo)準(zhǔn)化設(shè)備坐標(biāo)的形式(OpenGL的可見(jiàn)區(qū)域)定義為一個(gè)float數(shù)組朋贬。
        由于OpenGL是在3D空間中工作的,而我們渲染的是一個(gè)2D三角形窜骄,我們將它頂點(diǎn)的z坐標(biāo)設(shè)置為0.0锦募。
        這樣子的話三角形每一點(diǎn)的深度(Depth,譯注2)都是一樣的邻遏,從而使它看上去像是2D的糠亩。
    */
    float vertices[] = {
         0.5f,  0.5f, 0.0f,  // top right
         0.5f, -0.5f, 0.0f,  // bottom right
        -0.5f, -0.5f, 0.0f,  // bottom left
        -0.5f,  0.5f, 0.0f   // top left 
    };
    unsigned int indices[] = {  // note that we start from 0!
        0, 1, 3,  // first Triangle
        1, 2, 3   // second Triangle
    };
    /*
        定義這樣的頂點(diǎn)數(shù)據(jù)以后,我們會(huì)把它作為輸入發(fā)送給圖形渲染管線的第一個(gè)處理階段:頂點(diǎn)著色器准验。
        它會(huì)在GPU上創(chuàng)建內(nèi)存用于儲(chǔ)存我們的頂點(diǎn)數(shù)據(jù)赎线,還要配置OpenGL如何解釋這些內(nèi)存,并且指定其如何發(fā)送給顯卡糊饱。
        頂點(diǎn)著色器接著會(huì)處理我們?cè)趦?nèi)存中指定數(shù)量的頂點(diǎn)垂寥。

        我們通過(guò)頂點(diǎn)緩沖對(duì)象(Vertex Buffer Objects, VBO)管理這個(gè)內(nèi)存,
        它會(huì)在GPU內(nèi)存(通常被稱為顯存)中儲(chǔ)存大量頂點(diǎn)另锋。
        使用這些緩沖對(duì)象的好處是我們可以一次性的發(fā)送一大批數(shù)據(jù)到顯卡上矫废,而不是每個(gè)頂點(diǎn)發(fā)送一次。
        從CPU把數(shù)據(jù)發(fā)送到顯卡相對(duì)較慢砰蠢,所以只要可能我們都要嘗試盡量一次性發(fā)送盡可能多的數(shù)據(jù)蓖扑。
        當(dāng)數(shù)據(jù)發(fā)送至顯卡的內(nèi)存中后,頂點(diǎn)著色器幾乎能立即訪問(wèn)頂點(diǎn)台舱,這是個(gè)非陈筛埽快的過(guò)程。
    */





    //頂點(diǎn)緩沖對(duì)象 
    //頂點(diǎn)數(shù)組對(duì)象
    
    unsigned int VBO, VAO, EBO;

    //使用glGenVertexArrays函數(shù)和一個(gè)緩沖ID生成一個(gè)VAO對(duì)象:
    glGenVertexArrays(1, &VAO);



    //VBO:
    //使用glGenBuffers函數(shù)和一個(gè)緩沖ID生成一個(gè)VBO對(duì)象:
    //OpenGL有很多緩沖對(duì)象類(lèi)型竞惋,頂點(diǎn)緩沖對(duì)象的緩沖類(lèi)型是GL_ARRAY_BUFFER柜去。
    //OpenGL允許我們同時(shí)綁定多個(gè)緩沖,只要它們是不同的緩沖類(lèi)型拆宛。
    
    glGenBuffers(1, &VBO);

    //EBO:
    //使用glGenBuffers函數(shù)和一個(gè)緩沖ID生成一個(gè)EBO對(duì)象:
    glGenBuffers(1, &EBO);


    //VAO:首先綁定頂點(diǎn)數(shù)組對(duì)象
    glBindVertexArray(VAO);

    //VBO:
    //我們可以使用glBindBuffer函數(shù)把新創(chuàng)建的緩沖綁定到GL_ARRAY_BUFFER目標(biāo)上:
    //從這一刻起嗓奢,我們使用的任何(在GL_ARRAY_BUFFER目標(biāo)上的)緩沖調(diào)用
    //都會(huì)用來(lái)配置當(dāng)前綁定的緩沖(VBO)。
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    //VAO:然后把頂點(diǎn)數(shù)組復(fù)制到緩沖中供OpenGL使用
    //VBO:然后我們可以調(diào)用glBufferData函數(shù)浑厚,把索引復(fù)制到緩沖里
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);


    //EBO:
    //我們可以使用glBindBuffer函數(shù)把新創(chuàng)建的緩沖綁定到GL_ARRAY_BUFFER目標(biāo)上:
    //從這一刻起股耽,我們使用的任何(在GL_ARRAY_BUFFER目標(biāo)上的)緩沖調(diào)用
    //都會(huì)用來(lái)配置當(dāng)前綁定的緩沖(VBO)。
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


    //VAO:最后設(shè)置頂點(diǎn)屬性指針
    //對(duì)glVertexAttribPointer的調(diào)用將VBO注冊(cè)為頂點(diǎn)屬性的綁定頂點(diǎn)緩沖區(qū)對(duì)象钳幅,因此之后我們可以安全地解除綁定
    //鏈接頂點(diǎn)屬性
    //每個(gè)頂點(diǎn)屬性從一個(gè)VBO管理的內(nèi)存中獲得它的數(shù)據(jù)物蝙,而具體是從哪個(gè)VBO(程序中可以有多個(gè)VBO)
    //獲取則是通過(guò)在調(diào)用glVertexAttribPointer時(shí)綁定到GL_ARRAY_BUFFER的VBO決定的。
    //由于在調(diào)用glVertexAttribPointer之前綁定的是先前定義的VBO對(duì)象敢艰,頂點(diǎn)屬性0現(xiàn)在會(huì)鏈接到它的頂點(diǎn)數(shù)據(jù)诬乞。
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    //我們現(xiàn)在應(yīng)該使用glEnableVertexAttribArray,以頂點(diǎn)屬性位置值作為參數(shù),啟用頂點(diǎn)屬性震嫉;頂點(diǎn)屬性默認(rèn)是禁用的
    glEnableVertexAttribArray(0);

    

    
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    //之后您可以解除綁定VAO森瘪,這樣其他VAO調(diào)用就不會(huì)意外修改此VAO,但這很少發(fā)生票堵。 修改其他
    // VAO無(wú)論如何都需要調(diào)用glBindVertexArray柜砾,因此通常在不需要時(shí),我們通常不會(huì)取消綁定VAO(也沒(méi)有VBO)换衬。
    glBindVertexArray(0);

    /*
    一般當(dāng)你打算繪制多個(gè)物體時(shí)痰驱,你首先要生成/配置所有的VAO(和必須的VBO及屬性指針),
    然后儲(chǔ)存它們供后面使用瞳浦。
    當(dāng)我們打算繪制物體的時(shí)候就拿出相應(yīng)的VAO担映,綁定它,繪制完物體后叫潦,再解綁VAO蝇完。
    */

    
    
    
    /*
    我們希望程序在我們主動(dòng)關(guān)閉它之前不斷繪制圖像并能夠接受用戶輸入。
    因此矗蕊,我們需要在程序中添加一個(gè)while循環(huán)短蜕,我們可以把它稱之為渲染循環(huán)(Render Loop),
    它能在我們讓GLFW退出前一直保持運(yùn)行傻咖。
    下面幾行的代碼就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的渲染循環(huán):
    */
    /*
    glfwWindowShouldClose函數(shù)在我們每次循環(huán)的開(kāi)始前檢查一次GLFW是否被要求退出朋魔,
    如果是的話該函數(shù)返回true然后渲染循環(huán)便結(jié)束了,之后為我們就可以關(guān)閉應(yīng)用程序了卿操。
    */
    while (!glfwWindowShouldClose(window))
    {
        // input
        // -----
        processInput(window);

        // render
        // ------
        //要把所有的渲染(Rendering)操作放到渲染循環(huán)中警检,
        //因?yàn)槲覀兿胱屵@些渲染指令在每次渲染循環(huán)迭代的時(shí)候都能被執(zhí)行。
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // draw our first triangle
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO); //我們只有一個(gè)VAO害淤,因此不必每次都綁定它扇雕,但是我們這樣做是為了使事情更有條理
        //glDrawArrays函數(shù),它使用當(dāng)前激活的著色器窥摄,之前定義的頂點(diǎn)屬性配置镶奉,和VBO的頂點(diǎn)數(shù)據(jù)(通過(guò)VAO間接綁定)來(lái)繪制圖元。
        
        
        //glDrawArrays(GL_TRIANGLES, 0, 3);
        //用glDrawElements來(lái)替換glDrawArrays函數(shù)崭放,來(lái)指明我們從索引緩沖渲染哨苛。
        //使用glDrawElements時(shí),我們會(huì)使用當(dāng)前綁定的索引緩沖對(duì)象中的索引進(jìn)行繪制:
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        /*
        glfwSwapBuffers函數(shù)會(huì)交換顏色緩沖(它是一個(gè)儲(chǔ)存著GLFW窗口每一個(gè)像素顏色值的大緩沖)莹菱,
        它在這一迭代中被用來(lái)繪制移国,并且將會(huì)作為輸出顯示在屏幕上。
        */
        /*
        glfwPollEvents函數(shù)檢查有沒(méi)有觸發(fā)什么事件(比如鍵盤(pán)輸入道伟、鼠標(biāo)移動(dòng)等)、更新窗口狀態(tài),
        并調(diào)用對(duì)應(yīng)的回調(diào)函數(shù)(可以通過(guò)回調(diào)方法手動(dòng)設(shè)置)
        */
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    //delete
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    /*
    當(dāng)渲染循環(huán)結(jié)束后我們需要正確釋放/刪除之前的分配的所有資源蜜徽。
    我們可以在main函數(shù)的最后調(diào)用glfwTerminate函數(shù)來(lái)完成祝懂。
    */
    glfwTerminate();
    return 0;
}

void processInput(GLFWwindow *window)
{
    //檢測(cè)是否按下esc,按下則退出循環(huán)
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}
  • 效果


    image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拘鞋,一起剝皮案震驚了整個(gè)濱河市砚蓬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盆色,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,865評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異于宙,居然都是意外死亡柴灯,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)宣旱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)仅父,“玉大人,你說(shuō)我怎么就攤上這事浑吟◇舷耍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,631評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵组力,是天一觀的道長(zhǎng)省容。 經(jīng)常有香客問(wèn)我,道長(zhǎng)燎字,這世上最難降的妖魔是什么蓉冈? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,199評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮轩触,結(jié)果婚禮上寞酿,老公的妹妹穿的比我還像新娘。我一直安慰自己脱柱,他們只是感情好伐弹,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,196評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著榨为,像睡著了一般惨好。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上随闺,一...
    開(kāi)封第一講書(shū)人閱讀 52,793評(píng)論 1 314
  • 那天日川,我揣著相機(jī)與錄音,去河邊找鬼矩乐。 笑死龄句,一個(gè)胖子當(dāng)著我的面吹牛回论,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播分歇,決...
    沈念sama閱讀 41,221評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼傀蓉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了职抡?” 一聲冷哼從身側(cè)響起葬燎,我...
    開(kāi)封第一講書(shū)人閱讀 40,174評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缚甩,沒(méi)想到半個(gè)月后谱净,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,699評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡擅威,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,770評(píng)論 3 343
  • 正文 我和宋清朗相戀三年壕探,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裕寨。...
    茶點(diǎn)故事閱讀 40,918評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡浩蓉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宾袜,到底是詐尸還是另有隱情捻艳,我是刑警寧澤,帶...
    沈念sama閱讀 36,573評(píng)論 5 351
  • 正文 年R本政府宣布庆猫,位于F島的核電站认轨,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏月培。R本人自食惡果不足惜嘁字,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,255評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望杉畜。 院中可真熱鬧纪蜒,春花似錦、人聲如沸此叠。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,749評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)灭袁。三九已至猬错,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間茸歧,已是汗流浹背倦炒。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,862評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留软瞎,地道東北人逢唤。 一個(gè)月前我還...
    沈念sama閱讀 49,364評(píng)論 3 379
  • 正文 我出身青樓拉讯,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親智玻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子遂唧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,926評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容