首页 > 其他分享 >OpenGL三角形

OpenGL三角形

时间:2023-05-27 15:34:06浏览次数:45  
标签:info OpenGL aPos 顶点 三角形 GL 着色器 vShader

先了解一下一些基础概念

图形渲染管线(graphics pipeline)
  • 指一堆图形数据输入到一个管道中,经过管道中一些列的处理后将结果展现到屏幕上的过程
    image
    简单来说可以认为有以下过程,每个阶段的输出都是下一个阶段的输入
  1. 顶点数据输入————就是输入一些顶点的位置数据,如三角形的顶点之类的
  2. 顶点着色器————跑在GPU上,以顶点数据为输入,可以对顶点数据进行变换(位移、旋转、比例转换等)
  3. 图元装配————将顶点着色器的输出组成图元(线段、三角形、矩形等)
  4. 几何着色器————以图元顶点集合为输入,可以通过生成新的顶点产生新的图元(例如再生成一个三角形之类的)
  5. 光栅化————把图元映射为屏幕上的像素,生成片段,执行裁切掉弃视图外的像素
  6. 片段着色器————计算一个像素的颜色
  7. 测试与混合————进行Alpha测试与混合(半透明的颜色需要和后面的颜色混合,非透明的颜色如果是直接遮挡后面的颜色,后面的颜色掉弃)
OpenGL的基本概念
  • 顶点缓冲对象(VBO, vertex buffer object)
    用来管理顶点的数据,顶点缓冲对象的数据位于显存中
      //triangle vertices
      float vertices[] = {
              -0.5, -0.5, 0,
              0.5, -0.5, 0,
              0, 0.5, 0
      };
      //create buffer
      GLuint vbo;
      glGenBuffers(1, &vbo);
      //bind VBO
      glBindBuffer(GL_ARRAY_BUFFER, vbo);
      //copy data from cpu mem to gpu mem
      glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
      //set vertex attribute
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), 0);
      glEnableVertexAttribArray(0);
      //unbind VBO
      glBindBuffer(GL_ARRAY_BUFFER, 0);
    
  • 顶点数组对象(VAO,vertex array object)
    用来管理一堆VBO的属性的对象
      GLuint VAO;
      glGenVertexArrays(1, &VAO);
      //bind VAO
      glBindVertexArray(VAO);
      //...省略VBO的属性设置 如上面代码所示
      //unbind VAO
      glBindVertexArray(0);
    
  • 元素缓冲对象(EBO, element buffer object;或者叫IBO, index buffer object索引缓冲对象)
    简单来说就是通过索引定位顶点,例如绘制两个三角形,他们之间有两个顶点位置是一样的,这样就只需要储存四个顶点,通过索引位置复用两个顶点的数据。
  • 标准化设备坐标(x、y、z坐标轴的范围都是[-1.0,1.0]之间)
    在OpenGL下经过顶点着色器处理后的坐标都应该为标准化设备坐标
  • OpenGL最少需要编写两个着色器,包括顶点着色器片段着色器
    创建着色器程序的步骤(以顶点着色器为例)
    1. 定义着色器的代码
      const char *vShaderSrc = "#version 330 core\n"
                            "layout (location = 0) in vec3 aPos;\n"
                            "void main() {\n"
                            "    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
                            "}";
    
    1. 创建着色器对象并绑定着色器代码
      GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
      glShaderSource(vShader, 1, &vShaderSrc, NULL);
    
    1. 编译着色器代码并检查编译错误
      glCompileShader(vShader);
      //error check
      GLint compileStatus;
      glGetShaderiv(vShader, GL_COMPILE_STATUS, &compileStatus);
      if (!compileStatus) {
          char info[512];
          glGetShaderInfoLog(vShader, sizeof(info), NULL, info);
          std::cout << "compile vShader error: " << info << '\n';
      }
    
    1. 定义片段着色器(省略步骤和顶点着色器的一致)
    2. 创建着色器程序并将顶点着色器及片段着色器关联上去
      GLuint program = glCreateProgram();
      glAttachShader(program, vShader);
      glAttachShader(program, fShader);
    
    1. 链接着色器程序并检查错误
      GLint linkStatus;
      glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
      if (!linkStatus) {
          char info[512];
          glGetProgramInfoLog(program, sizeof(info), NULL, info);
          std::cout << "link error: " << info << '\n';
      }
    
    1. 清理顶点着色器及片段着色器
      glDeleteShader(vShader);
      glDeleteShader(fShader);
    
绘制两个三角形的程序结构
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>

void framebufferSizeChanged(GLFWwindow *glfwWindow, int width, int height);
void processInput(GLFWwindow *glfwWindow);

GLuint createShaderProgram() {
    //vShader
    const char *vShaderSrc = "#version 330 core\n"
                          "layout (location = 0) in vec3 aPos;\n"
                          "void main() {\n"
                          "    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
                          "}";
    //compile vShader
    GLuint vShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vShader, 1, &vShaderSrc, NULL);
    glCompileShader(vShader);
    //error check
    GLint compileStatus;
    glGetShaderiv(vShader, GL_COMPILE_STATUS, &compileStatus);
    if (!compileStatus) {
        char info[512];
        glGetShaderInfoLog(vShader, sizeof(info), NULL, info);
        std::cout << "compile vShader error: " << info << '\n';
    }


    const char *fShaderSrc = "#version 330 core\n"
                             "out vec4 fragColor;\n"
                             "void main() {\n"
                             "    fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
                             "}";
    GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fShader, 1, &fShaderSrc, NULL);
    glCompileShader(fShader);

    glGetShaderiv(fShader, GL_COMPILE_STATUS, &compileStatus);
    if (!compileStatus) {
        char info[512];
        glGetShaderInfoLog(vShader, sizeof(info), NULL, info);
        std::cout << "compile fShader error: " << info << '\n';
    }

    GLuint program = glCreateProgram();
    glAttachShader(program, vShader);
    glAttachShader(program, fShader);
    glLinkProgram(program);

    GLint linkStatus;
    glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
    if (!linkStatus) {
        char info[512];
        glGetProgramInfoLog(program, sizeof(info), NULL, info);
        std::cout << "link error: " << info << '\n';
    }

    glDeleteShader(vShader);
    glDeleteShader(fShader);

    return program;
}

int main() {
    //初始化glfw
    if (!glfwInit()) {
        return -1;
    }

    //创建窗口
    GLFWwindow *glfwWindow = glfwCreateWindow(640, 480, "glfw_window", NULL, NULL);
    if (!glfwWindow) {
        glfwTerminate();
        return -1;
    }

    //将当前的context关联到glfwWindow
    glfwMakeContextCurrent(glfwWindow);
    glfwSetFramebufferSizeCallback(glfwWindow, framebufferSizeChanged);

    //glad需要要在glfwMakeContextCurrent后才能初始化
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
        glfwTerminate();
        return -1;
    }

    //triangle vertices
    float vertices[] = {
            -0.5, -0.5, 0,
            0.5, -0.5, 0,
            -0.5, 0.5, 0,
            0.5, 0.5, 0
    };

    unsigned int indices[] = {
            0, 1, 2,
            1, 2, 3
    };

    GLuint VAO;
    glGenVertexArrays(1, &VAO);
    //create buffer
    GLuint VBO, EBO;
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    //bind VAO
    glBindVertexArray(VAO);

    //bind VBO
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    //copy data from cpu mem to gpu mem
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    //bind EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    //set vertex attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), 0);
    glEnableVertexAttribArray(0);
    //unbind VBO
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    //do not unbind EBO, EBO store in VAO
    //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    //unbind VAO
    glBindVertexArray(0);

    GLuint program = createShaderProgram();

    //消息循环
    while(!glfwWindowShouldClose(glfwWindow)) {
        processInput(glfwWindow);

        glClearColor(0.0, 0.0, 0, 1.0);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(program);
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

        glfwSwapBuffers(glfwWindow);
        glfwPollEvents();
    }

    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteProgram(program);

    glfwTerminate();
    return 0;
}

void framebufferSizeChanged(GLFWwindow *glfwWindow, int width, int height) {
    glViewport(0, 0, width, height);
}

void processInput(GLFWwindow *glfwWindow) {
    if (glfwGetKey(glfwWindow, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(glfwWindow, true);
    }
}
OpenGL的函数参考文档doc

标签:info,OpenGL,aPos,顶点,三角形,GL,着色器,vShader
From: https://www.cnblogs.com/noexcept/p/17436457.html

相关文章