图形管道(pipeline)

9.3 图形管道
9.3.1 pipeline

​ 图形管道是将 3D 坐标转换为 2D 像素,图形管道可以分为两大部分:第一部分将 3D 坐标转换为 2D 坐标,第二部分将 2D 坐标转换为实际的彩色像素。

Vertex Data -----> Vertex SHADER -------->GEOMETRY SHADER ------->RASTERIZATION------>FRAGMENT SHADER -----> TEST AND BLENDING

顶点数据 -------> 顶点着色器 ------------> 几何着色器 ------------> 光栅化 -------->片段着色器----->测试和混合

9.3.2 VBO

​ VBO 是显存中的一片缓冲区域,存放从内存中提交过来的顶点数据。GPU 绘制时,需要对 VBO 中的数据进行解析,以便将数据正确的提交给着色器中对应的属性。

glVertexAttribPointer的作用:GPU 需要知道 VBO 中哪一块数据是某个顶点的坐标,哪一块数据是某个顶点的顶点颜色等,通过调用 glVertexAttribPointer 方法来设置解析规则

(1)使用步骤:

创建缓冲区,绑定对象,设置数据,使用对象,清理数据

具体参考博客:https://blog.csdn.net/qq_36383623/article/details/85123077

c++ 复制代码
//第一步:生成和绑定VBO
unsigned int VBO;
glGenBuffers(1, &VBO);//这里的1表示VBO的数量
glBindBuffer(GL_ARRAY_BUFFER, VBO);//设置属性

//第二步:传递顶点数据到 VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

//第三步:使用VBO
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0); //启动顶点属性

//第四步:清理资源
glDeleteBuffers(0, &VBO);

(2)函数解析

a. glGenBuffersg和lBindBuffer作用:glGenBuffersg在GPU上生成缓冲区对象;glBindBuffer是讲缓冲对象设置为数组缓冲对象;

注意此处VBO是unsigned int类型,是指缓冲区对象的标识符;

b. 设置数据

c++ 复制代码
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

函数作用:数据复制到当前绑定缓冲的函数

第一个参数是目标缓冲的类型:顶点缓冲,成员顶点缓冲

第二个参数指定传输数据的大小

第三个参数是实际数据

第四个参数指定了管理给定的数据:

GL_STATIC_DRAW:数据不会或几乎不会改变。

GL_DYNAMIC_DRAW:数据会被改变很多。

GL_STREAM_DRAW :数据每次绘制时都会改变。

c. 使用VBO:

c++ 复制代码
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Position));
glEnableVertexAttribArray(0);
  • 第一个参数顶点属性。使用指定了顶点着色器的位置layout (location = 0)
  • 第一个参数指定顶点属性的大小。顶点属性是一个vec3,因此它由值组成3
  • 第三个参数指定数据类型GL_FLOAT由浮点值组成。
  • 第四个参数指定是否希望数据标准化
  • 第五个参数称为跨步,下一组位置数据是距离大小的 3 倍处,因此float我们将该值指定为步幅。
  • 第六个参数是偏移量,表示数据起始位置
9.3.3 VAO

VBO 是为了向GPU传递顶点数据,那么VAO就是为了向GPU解释顶点数据具体参考博客:https://blog.csdn.net/danshiming/article/details/56286880

c++ 复制代码
     unsigned int VBO, VAO;
    glGenVertexArrays(1, &VAO);//生成1个VAO
    glGenBuffers(1, &VBO);//生成一个VBO
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);//绑定VBO
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//将顶点数据传递到VBO

    // position attribute 位置属性和颜色属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);//将当前顶点属性与VBO关联
    glEnableVertexAttribArray(0);//启动顶点属性
    // color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
9.3.4 VBO/EBO 和VAO的使用

EBO(Element Buffer Object,元素缓冲区对象)是 OpenGL 中用于存储索引数据的缓冲区对象

VBO/EBO 和VAO 只有在创建缓冲对象是不一样的,后面部分代码是共用的;

c++ 复制代码
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <iostream>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);

const char *vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "layout (location = 1) in vec3 aColor;\n"
    "out vec3 ourColor;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos, 1.0);\n"
    "   ourColor = aColor;\n"
    "}\0";
const char *fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "in vec3 ourColor;\n"
    "void main()\n"
    "{\n"
    "   FragColor = vec4(ourColor, 1.0f);\n"
    "}\n\0";

int main()
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // 创建顶点着色器对象
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
    glCompileShader(vertexShader);
    // 检查顶点着色器是否编译成功
    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;
    }

    // 创建片段着色器对象
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
    glCompileShader(fragmentShader);
    // 检查片段着色器是否编译成功
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    // 创建着色器程序
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    // 检查着色器程序是否链接成功
    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);

    // 定义三角形的顶点数据
    float vertices[] = {
        // 位置             // 颜色
         0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f, // 右下角
        -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f, // 左下角
         0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f  // 顶部
    };

    // 创建并绑定 VAO
    GLuint VAO, VBO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    // 设置顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // 解绑 VBO 和 VAO
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    // 渲染循环
    while (!glfwWindowShouldClose(window))
    {
        processInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // 释放资源
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    glDeleteProgram(shaderProgram);

    glfwTerminate();
    return 0;
}

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

void processInput(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}
相关推荐
ZZZ_O^O20 分钟前
二分查找算法——寻找旋转排序数组中的最小值&点名
数据结构·c++·学习·算法·二叉树
小飞猪Jay3 小时前
C++面试速通宝典——13
jvm·c++·面试
rjszcb3 小时前
一文说完c++全部基础知识,IO流(二)
c++
小字节,大梦想4 小时前
【C++】二叉搜索树
数据结构·c++
吾名招财4 小时前
yolov5-7.0模型DNN加载函数及参数详解(重要)
c++·人工智能·yolo·dnn
我是哈哈hh5 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
憧憬成为原神糕手5 小时前
c++_ 多态
开发语言·c++
郭二哈5 小时前
C++——模板进阶、继承
java·服务器·c++
挥剑决浮云 -5 小时前
Linux 之 安装软件、GCC编译器、Linux 操作系统基础
linux·服务器·c语言·c++·经验分享·笔记
丶Darling.5 小时前
LeetCode Hot100 | Day1 | 二叉树:二叉树的直径
数据结构·c++·学习·算法·leetcode·二叉树