OpenGL基本架构知识

OpenGL基本架构知识

环境:Qt Creator + C++

参考书籍:《计算机图形学编程(使用OpenGL和C++)》作者:V.斯科特.戈登 约翰.克莱维吉 (人民邮电出版社)

参考博客:https://blog.csdn.net/weixin_59876363/article/details/122570371

一、绪论

简介
  1. OpenGL是什么

    • 用于渲染2D和3D矢量图形的跨语言、跨平台的应用程序编程接口(API)
    • 提供了多级图形管线和GLSL(高级着色语言)进行模型的像素化
    • 核心库使用c编写,同时支持多种系统和语言
  2. 核心模式/可编程管线模式:
    将顶点数据经过管线处理,最终生成显示的像素点。以下为渲染顺序:

    • 顶点着色器:必须自己实现,依靠顶点数据和着色器指令控制顶点的渲染位置和方式
    • 曲面细分着色器:可以在简单图形上生成大量网格图元(常用的是三角)
    • 几何着色器:赋予程序员一次处理一个图元(多个顶点)的能力(常用的是三角)
    • 光栅化:将输入的图元转化成二维图像片段,即像素绘制的片段
    • 片段着色器:为光栅化的像素点指定颜色
    • 测试与混合
  3. GLSL运行在GPU上,OS不是总能捕捉运行的错误,通常需要进行GLSL运行日志的打印进行debug

  4. GLSL代码加载进入着色器的过程

    • C++获取GLSL着色器代码,可以在文件中读取,也可以硬编码在字符串中
    • 创建OpenGL空着色器对象并将GLSL着色器代码加载进着色器对象(一般至少要提供顶点着色器和片段着色器的代码,其他着色器代码是可选的)
    • 最后使用OpenGL命令编译链接着色器对象,并将该对象加载进硬件
  5. QOpenGLWidget提供了三个便捷的虚函数,可以进行重载实现典型的OpenGL任务

    • initializeGL:初始化设置OpenGL资源和状态
    • paintGL:渲染OpenGL场景,widget需要进行实时更新的调用
    • resizeGL:设置OpenGL视口和投影等。widget调整大小时调用
  6. 顶点着色器会在GPU上创建内存,通过GL_ARRAY_BUFFER缓冲类型的顶点缓冲对象进行管理,每一个VBO记录了一种状态。

    • 数据:从内存加载顶点缓冲对象(Vertex Buffer Objects ,VBO)到的显存中
    • 规则:通过顶点数组对象(Vertex Array Object,VAO)对顶点数据进行解释
  7. OpenGL是一个巨大的状态机,数据输入后,绘制状态参数(材质,光照,连接方式···)决定了输出的图像。OpenGL通过改变上下文变量来改变OpenGL状态,从而告知OpenGL如何绘制图像

  8. 在paintGL之外的地方调用绘制函数,没有意义,绘制图像最终将被paintGL()覆盖。如果不想被覆盖则应该使用widget的update()函数进行安排和更新

缓冲区对象
  1. 缓冲区绑定流程

    // 1.声明VBO和VAO
    GLuint vao[1];// GLuint实际就是unsigned int
    GLuint vbo[2];
    // 2.创建缓冲区,并将返回的ID存入VAO和VBO
    glGenVertexArrays(1, &VAO);
    glGenBuffers(2, &VBO);// (创建ID的数目, 用来保存返回ID的数组)
    // 3.将VAO和VBO绑定成缓冲区对象
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    // 4. 初始化缓冲区数据
    glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);
    // 5. 告诉GPU如何解释VBO中的属性信息
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), nullptr);
    // 6. 启用0号顶点属性
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float),  (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    // 7. 使用glDrawArrays()绘制对象
    
  2. 着色器的绑定:每个缓冲区需要有在顶点着色器中声明的相应的顶点属性变量

    layout(location = 0) in vec3 position
    // 位置值为0的顶点属性指针指向的数据,每次抓取3个到position中
    
    • layout修饰符是将顶点属性和特定缓冲区关联的方法,这里的0就是绑定的0号ID的VBO
    • in关键字表示顶点属性从缓冲区接收数值
    • vec3的意思是着色器每次调用会抓取三个浮点类型的值,即一个坐标(x, y, z)
    • 变量名称是position
  3. 通常把顶点数据放在一个缓冲区中,并把这个缓冲区和着色器中声明的顶点属性相关联

  4. 在OpenGL中,缓冲区被包含在顶点缓冲对象(Vertex Buffer Object, VBO)中,VBO在C++/OpenGL应用程序中被声明和实例化。一个场景可能需要很多个VBO,通常我们在初始化的阶段生成并填充若干个VBO,方便后续直接使用。

  5. 使用uniform关键字在着色器中声明统一变量

GLSL
  1. GLSL(OpenGL Shading Language)使用C语言作为基础高阶着色语言,避免了使用汇编语言或硬件规格语言的复杂性。

    // 典型程序
    #version version_number
    in type in_variable_name;
    in type in_variable_name;
    out type out_variable_name;
    uniform type uniform_name;
    
    void main(){
        out_variable_name = weird_stuff_we_processed;
    }
    
  2. OpenGL确保至少有16个包含4分量的顶点属性可以使用,但是可以声明的顶点属性数量存在上限

  3. GLSL的容器

    • 向量(Vetor)
      • vecn:n个float类型
      • bvecn:n个boolean类型
      • ivecn:n个intgers类型
      • uvecn:n个无符号整形
      • dvecn:n个double类型
    • 矩阵(Matrix)
  4. 向量重组

    vec2 vect = vex2(0.5, 0.7);
    vec4 result = vex4(vect, 0.0, 0.0);
    
  5. 如果类型和名字都一致,OpenGL可以把不同程序文件变量都链接在一起

    
    #version 330 core
    // 顶点着色器定义和声明变量
    layout (location = 0) in vec3 aPos;
    out vec4 vertexColor;
    void main() {
        gl_Position = vec4(aPos, 1.0);
        vertexColor = vec4(0.5, 0.0, 0.0, 1.0);
    }
    
    
    #version 330 core
    // 片段着色器接受变量
    out vec4 FragColor;
    in vec4 vertexColor;// 接收的变量
    void main() {
        FragColor = vertexColor; 
    }
    

    如果将它们封装在单独的资源文件中,使用shaderProgram.addShaderFromSourceFile()函数进行连接,则首行必须是版本号

  6. paintGL()以外的位置绘制openGL

    makeCurrent();
    // openGL绘制函数
    doneCurrent();
    update();
    

    如果不使用上述函数进行包含,绘制的图像将会被paintGL( )覆盖

  7. 顶点着色器的输入来源于openGL形式化的数据,使用layout(location = 0)链接到顶点数据,可以在cpu上配置顶点属性

  8. GPU和CPU之间的数据传输

    • 使用glGetAttribLocation查村属性位置值
    • 绑定GPU的属性值,告诉它向cpu解析的属性值
    // 1.属性值查询的方式
    shaderProgram.bind();
    // 查询属性位置值,如果查询不到返回-1
    Glint posLocation = shaderProgram.attributeLocation("aPos");
    // 告诉显卡如何解析缓冲里的属性值
    glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float),(void*)0);
    
    // 2.绑定的方式
    shaderProgram.bind();
    GLint posLocation = 2;
    shaderProgram.bindAttributeLocation("aPos", poslocation);
    glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0);
    // 开始VAO管理的第三个属性值
    glENableVertexAttribArray(posLocation);
    
  9. uniform是一种CPU向GPU中着色器发送数据的方式,是全局的Global,可以被任意着色器程序在任意阶段访问

    • 如果声明一个uniform却没有用过,编译器会默认移除这个变量,导致最后编译出的版本中并不会包含它,这可能导致几个非常麻烦的错误
    • OpenGL在其核心是一个c库,所以不支持类型的重载 ,在函数参数类型不同时,需要为其定义新的函数。
  10. 在Qt中可以使用QTimer的timeout信号槽,传递一个随着时间改变的值

  11. 将顶点着色器中的数据传到片段着色器中

    // 顶点着色器
    #version 330 core
    layout(location = 0) in vec3 aPos;
    layout(location = 1) in vec3 aColor;
    out vec3 ourColor;# 传递的值
    void main(){
        gl_Position = vex4(aPos, 1.0);
        ourColor = aColor;
    }
    
    // 片段着色器
    #version 330 core
    out vec4 FragColor;
    in vec3 ourColor;
    
    void main(){
        FragColor = vec4(ourColor, 1.0);
    }
    
纹理处理
  1. 当出现复杂图形绘制时候通常采用纹理贴图采样的方式,即对一个图片进行裁剪后的部分显示

https://blog.csdn.net/weixin_59876363/article/details/122807398

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逆羽飘扬

如果有用,请支持一下。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值