• OpenGL之渲染管线VBOVAO 三角形示例 安静点


    在OpenGL中,一切都是3D的,但屏幕或窗口是一个2D像素阵列,因此OpenGL的大部分工作是将所有3D坐标转换为适合屏幕的2D像素。这个过程由OpenGL的渲染管线管理。

    渲染管线可以分为两大部分:

    • 将3D坐标转换为2D坐标
    • 将2D坐标转换为实际的彩色像素

    顶点着色器处理后,顶点值应该是NDC坐标;NDC坐标使用glViewport提供的数据,通过视口转换变为屏幕坐标。生成的屏幕空间坐标将转换为片段,作为片段着色器的输入。

    标准化设备坐标 (Normalized Device Coordinates, NDC)

    顶点着色器中处理过后,就应该是标准化设备坐标了,x、y 和 z 的值在-1.0到1.0的一小段空间(立方体)。落在范围外的坐标都会被裁剪。

     

      

    顶点输入

    在GPU上创建内存,储存的顶点数据

    • 通过顶点缓冲对象(Vertex Buffer Objects, VBO)管理
    • 顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER

    配置OpenGL如何解释这些内存

    • 通过顶点数组对象(Vertex Array Objects, VAO)管理

    使用缓冲区对象的优点是,可以一次将大量数据发送到显卡,不必一次发送一个数据。

    VAO并不保存实际数据,而是放顶点结构定义 数组里的每一个项都对应一个属性的解析

    必须使用VAO,OpenGL才能知道如何处理顶点输入。如果没有绑定VAO,OpenGL会拒绝绘制任何东西。

    OpenGL允许我们同时绑定多个缓冲,只要它们是不同的缓冲类型。 (每一个缓冲类型类似于前面说的子集,每个VBO是一个小助理)

    下图展示了VBO和VAO:

     

      下面是使用的关键代码:

    //创建VBO和VAO对象,并赋予ID
    unsigned int VBO, VAO; 
    //创建1个VAO对象
    glGenVertexArrays(1, &VAO); 
    //创建1个VBO对象
    glGenBuffers(1, &VBO); 
    //绑定VBO和VAO对象
    glBindVertexArray(VAO); 
    //缓冲对象如果绑定的是顶点属性则用:GL_ARRAY_BUFFER
    glBindBuffer(GL_ARRAY_BUFFER, VBO); 
    //为当前绑定到target的缓冲区对象创建一个新的数据存储。
    //如果data不是NULL,则使用来自此指针的数据初始化数据存储
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    //上面我们将数据存到了缓冲区对象中,下面就需要
    //告知Shader(着色器)如何解析缓冲里的属性值
    //第一个属性是从哪个位置开始解析
    //第二个属性是每个顶点属性由几个组合而成
    //第三个属性是数组中每个元素的类型
    //第四个表示是否标准化,这里暂时不需要,需要注意只有整型值才会有效,如果浮点型的数据不会起作用
    //第五个是步长,因为我们这个是数组中每3个元素组成一个顶点属性,而且是float类型
    //第六个是偏移量,我们这里为0,就是从0开始读取数组中的数据的
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    //开启VAO管理的第一个属性值
     glEnableVertexAttribArray(0); 
    //作为习惯,用完之后将VBO,VAO解绑,需要的时候可以重新绑定, 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 
    glBindVertexArray(0); 

     然后创建一个三角形的示例: 

    // GLAD的include文件包含所需的OpenGL头文件(如GL/GL.h),因此确保在其他需要OpenGL的头文件(如GLFW)之前包含GLAD。就是#include <glad/glad.h> 放在最前面
    #include <glad/glad.h> 
    #include <GLFW/glfw3.h>
    #include <iostream>
    float vertices[] = {
    -0.5f, -0.5f, 0.0f,
    0.5f, -0.5f, 0.0f,
    0.0f, 0.5f, 0.0f
    };
    
    void framebuffer_size_callback(GLFWwindow* window, int width, int height);
    void processInput(GLFWwindow* window);
    
    int main() {
        // 初始化GLFW,只有初始化完成之后才能够使用GLFW的函数
        glfwInit();
        // GLFW配置设置
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
        // 如果是苹果系统的话使用下面代码
    #ifdef __APPLE__ 
        glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    #endif  
    
        // 创建窗口 大小和名称
        GLFWwindow* window = glfwCreateWindow(800, 600, "LearnOpenGL", NULL, NULL);
        if (window == NULL) {
            std::cout << "Failed to create GLFW window" << std::endl;
            // 此函数销毁所有剩余的窗口和光标
            glfwTerminate();
            return -1;
        }
        //GLFW将窗口的上下文设置为当前线程的上下文
        glfwMakeContextCurrent(window);
        // 告诉GLFW我们希望每当窗口调整大小的时候调用这个函数
        glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
        //GLAD
        // glad: 加载所有OpenGL函数指针
        if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
            std::cout << "Failed to initialize GLAD" << std::endl;
            return -1;
        }
    
    
        //创建VBO和VAO对象,并赋予ID
        unsigned int VBO, VAO;
        //创建1个VAO对象
        glGenVertexArrays(1, &VAO);
        //创建1个VBO对象
        glGenBuffers(1, &VBO);
        //绑定VBO和VAO对象
        glBindVertexArray(VAO);
        //缓冲对象如果绑定的是顶点属性则用:GL_ARRAY_BUFFER
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        //为当前绑定到target的缓冲区对象创建一个新的数据存储。
        //如果data不是NULL,则使用来自此指针的数据初始化数据存储
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
        //上面我们将数据存到了缓冲区对象中,下面就需要
        //告知Shader(着色器)如何解析缓冲里的属性值
        //第一个属性是从哪个位置开始解析
        //第二个属性是每个顶点属性由几个组合而成
        //第三个属性是数组中每个元素的类型
        //第四个表示是否标准化,这里暂时不需要,需要注意只有整型值才会有效,如果浮点型的数据不会起作用
        //第五个是步长,因为我们这个是数组中每3个元素组成一个顶点属性,而且是float类型
        //第六个是偏移量,我们这里为0,就是从0开始读取数组中的数据的
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
        //开启VAO管理的第一个属性值
        glEnableVertexAttribArray(0);
        //作为习惯,用完之后将VBO,VAO解绑,需要的时候可以重新绑定
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
    
    
        // 渲染循环 一个循环就是一帧 只要是窗体不关闭,就会一直循环
        while (!glfwWindowShouldClose(window)) {
            processInput(window);
    
            // 在这里,我们将屏幕设置为了类似黑板的深蓝绿色
            glClearColor(0.2f, 0.3f, 0.3f, 1.0f); //状态设置
            // 调用glClear函数,清除颜色缓冲之后,整个颜色缓冲都会被填充为glClearColor里所设置的颜色。
            glClear(GL_COLOR_BUFFER_BIT); //状态使用
    
             #pragma region 绘制三角形
            //要注意的是前面我们已经解绑了VAO,所以现在是无法解析数据的,所以我们需要重新绑定,
            // 至于数据我们已经存到缓冲区了
            glBindVertexArray(VAO);
            // 从数据数组中indexwei=0处开始读取,每三个做一个三角形的顶点(这是在VAO中定义的)。第三个参数是说一共绘制三个顶点数据(每个顶点由vertices数组中的3个元素组成)
            glDrawArrays(GL_TRIANGLES, 0, 3);
            #pragma endregion
    
            // glfw: 交换缓冲区 该函数在指定窗口的前后缓冲区交换
            // 前缓冲区:屏幕上显示的图像
            // 后缓冲区:正在渲染的图像
            // glfwSwapBuffers函数会交换颜色缓冲(它是一个储存着GLFW窗口每一个像素颜色值的大缓冲),
            // 它在这一迭代中被用来绘制,并且将会作为输出显示在屏幕上
            glfwSwapBuffers(window);
            // 轮询IO事件(按键按下 / 释放、鼠标移动等)通过下面方法就可以是得窗体对鼠标做出的动作做出反应,比如关闭,移动窗体等
            glfwPollEvents();
        }
        // glfw: 回收前面分配的GLFW先关资源. 一定要注意,只有关闭窗体之后才会跳出while循环走到这一步!!!
        glfwTerminate();
        return 0;
    }
    // glfwGetKey函数:需要一个窗口以及一个按键作为输入;函数将会返回这个按键是否正在被按下
    void processInput(GLFWwindow* window)
    {
        // 如果按下了ESC键,设置窗体的关闭标志为true,代表窗体可以退出
        if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
            glfwSetWindowShouldClose(window, true);
    }
    
    // 当改变窗口的大小的时候,视口也应该被调整。我们可以对窗口注册一个回调函数(Callback Function),它会在每次窗口大小被调整的时候被调用
    void framebuffer_size_callback(GLFWwindow* window, int width, int height)
    {
        // 设置窗口维度
        // glViewport(前两参数为窗口左下角位置,3.宽度,4.高度)
        glViewport(0, 0, width, height);
    }

      结果:

     

     我们还没做着色器,所以这里的三角形颜色是根据自己电脑本身的默认颜色。 

  • 相关阅读:
    应用JConsole学习Java GC
    删除MySQL重复数据
    Linux后台运行程序
    Jvm基础(2)-Java内存模型
    一个word合并项目的分布式架构设计
    Jvm基础(1)-Java运行时数据区
    【JPA】01 快速上手
    【Ubuntu】下载安装 20.04.版本 桌面端
    【Ubuntu】下载安装 12.04.5版本 桌面端
    【CentOS】tar包安装Tomcat
  • 原文地址:https://www.cnblogs.com/anjingdian/p/16637702.html
Copyright © 2020-2023  润新知