基本名词

图元

图形渲染管道的输入量是几何图元(比如,三角形,点,直线或者四边形),它们都可以通过一个或者若干个几何顶点来描述。OpenGL支持三种类型的几何图元:点,线段和封闭的多边形。它们都是通过顶点来描述。每个顶点都有几个特定的属性,比如位置,颜色,法线和纹理。OpenGL提供了10种图元(如下图)。球体,三维盒子,角锥体都不是图元,它们都是可以通过图元组合生成。

顶点

顶点可以说是用来描述图元的基本单位,三维中,三角形图元需要三个点空间点确认,而这个空间点就是顶点。四边形由四个顶点组成,点图元就使用一个顶点就行。

如上图正方形,由6个四边形图元组成,每个四边形图元又由四个顶点描述。

顶点数组对象 VAO(Vertex Arrary Object)

顶点缓冲对象 VBO(Vertex Buffer Objects)

索引缓冲对象 EBO(Element Buffer Object)

其他

  1. Rendering(渲染): 把数学和图形数据转换成3D空间图像的操作或指图像。
  2. Transformaton(转换): 把2D下的点连接,使得观察者产生3D的错觉。
  3. Projection(投影): 把3D坐标转换为2D屏幕坐标。
  4. Rasterization(光栅化): 绘制或填充每个定点之间的像素形成线段。在大多数渲染的情况下,我们并不使用线段,而是用实心三角形进行渲染。将每个图元转换为一系列的碎片。我们可以认为一个碎片就是三维空间中的一个像素,同样具有位置,颜色,法线和纹理属性。
  5. Shading(着色): 改变顶点间的表面的颜色值。
  6. Shader(着色器): 在图形硬件上执行的单独程序,用来处理顶点和执行光栅化。
  7. Texture Mapping(纹理贴图): 把图片贴到三角形或多边形上,使3D效果更加显著。
  8. Blending(混合): 把不同颜色混在一起。可以在一个图形中绘制另一个图形,使得效果真实。
  9. 顶点处理:对模型的各个顶点进行计算(着色)以及坐标变换

3D图像渲染管道


包括以下几个主要步骤:

  1. 顶点处理: 对模型的各个顶点进行计算(着色)以及坐标变换
  2. 光栅化: 将每个图元转换为一系列的碎片。我们可以认为一个碎片就是三维空间中的一个像素,同样具有位置,颜色,法线和纹理属性。
  3. 碎片处理: 光栅化之后,我们得到一些列的碎片,这个阶段则是对碎片进行处理(着色)
  4. 合并输出: 将所有的碎片(3D概念中)转化成二维的颜色像素,最后输出显示到屏幕上

上述步骤中,顶点处理和碎片处理是可编程的。你可以编写顶点着色程序和碎片着色程序,来实现顶点和碎片的自定义运算处理。

一般着色程序使用类似C语言的高级语言编写,比如GLSL(OpenGL Shading Language),HLSL(High-Level Shading Language for Miscrosoft Direct3D),或者Cg(C for Graphics by NVIDIA)。

此外,光栅化和合并输出两个步骤是不可编程的,但是可以配置GPU中处理这两个步骤的一些参数。

opengl接口

可参考文章:https://www.cnblogs.com/linkzijun/p/6196172.html

编程

QT中为我们把OpenGL进行了封装,使用较原生OpenGL简单,除了对OpenGL原生接口的支持,QGLWidget还为OpenGL在多个操作系统平台上的应用进行了浅层封装。

qt支持Opengl的类

1、在Qt中为OpenGL提供支持的类主要有以下几个:

  1. OpenGLWindow
  2. QOpenGLWidget
  3. QOpenGLFunctions
  4. QOpenGLBuffer
  5. QGLWidget:用于渲染OpenGL场景的易于使用的Qt部件。
  6. QGLColormap:用于在QGLWidget中安装用户自定义的颜色图。
  7. QGLContext:封装了用于OpenGL渲染的场景。
  8. QGLFormat:指定OpenGL演染场景的显示模式。
  9. QGLFrameBufferObjectQGLPixelBuffer分别提供了对GL帧缓冲对象和GL像素缓冲的支持。
  10. QGLPaintEngine:QPaintEngine的派生类,为QPainter提供了OpenGL绘图引擎。

2、添加opengl模块及动态库

添加模块。

QT += opengl

有时候编译很多报错,动态库方向的,那就是没有添加对应的动态库,项目文件中添加对应库。

win32:LIBS += -lOpengl32 \-lglu32 \-lglut

4、虚函数接口

在QT中写OpenGL需要继承自QOpenGLWidget,QOpenGLWidget提供了三个虚函数用以重载来实现OpenGL的绘制。

  1. initializeGL() 注册函数:
    设置GL的渲染绘制属性、定义显示列表、载入固定纹理等初始化工作。在initializeGL()在调用paintGL()之前只被调用一次,之后不再调用。

  2. paintGL() 绘制函数:
    在此使用OpenGL中的接口进行场景绘制,QGLWidget的paintEvent( QPaintEvent* )将会自动调用 paintGL()进行部件的显示绘制。也可在需要重绘时通过updateGL()时调用paintGL(),和paintEvent使用基本相似。

  3. resizeGL() 该函数:
    用于处理当部件大小发生改变时,对OpenGL绘图管线各矩阵需要进行的操作。该函数paintGL()第一次调用之前,initializeGL()调用之后被第一次被调用, 之后每当QGLWidget的不见大小发生改变时,都将调用该函数来对视图、投影矩阵等进行相应的设置。

5、VBO的创建以及配置

 GLuint vbo_id;      glGenBuffers(1, &vbo_id);   //开辟显存空间并分配VBO的IDglBindBuffer(GL_ARRAY_BUFFER, vbo_id); //创建VBO并绑定ID//把用户定义的数据传输到当前的vbo_idglBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//告知OpenGL如何解释这些顶点数据glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);

OpenGL中所有的图形都是通过分解成三角形的方式进行绘制,glDrawArrays函数负责把模型绘制出来。

 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

函数原型:glDrawArrays (GLenum mode, GLint first, GLsizei count)

顶点属性glVertexAttribPointer默认是关闭的,使用时要以顶点属性位置值为参数调用glEnableVertexAttribArray开启。如:

 glEnableVertexAttribArray(0);......glDisableVertexAttribArray(0);

6、VAO的创建和配置

 GLuint vao_Id;glGenVertexArrays(1, &vao_Id);glBindVertexArray(vao_Id);

VAO是一个保存了所有顶点数据属性的状态结合,它存储了顶点数据的格式以及顶点数据所需的VBO对象的引用。VAO本身并没有存储顶点的相关属性数据,这些信息是存储在VBO中的,VAO相当于是对很多个VBO的引用,把一些VBO组合在一起作为一个对象统一管理。

7、EBO的创建和配置

和EBO差不多,只是VBO存储的顶点数据,EBO存储的是索引数据(索引顶点的)

    GLuint EBO;glGenBuffers(1, &EBO);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

当用EBO绑定顶点索引的方式绘制模型时,需要使用glDrawElements而不是glDrawArrays

8、两个例子

  1. 使用VBO,VAO绘制一个矩形图形。即直接依据VBO中的顶点数据绘制。
  2. 使用EBO绘制两个三角形,组成同样的矩形图形。使用EBO中的索引查找绘制,此方法节省共用的顶点数据,所以节省顶点数据内存,后期基本都是使用此方法。

例子1:

//使用VAO VBO绘制矩形
#include <GL/glew.h>
#include <GL/freeglut.h>  void userInit();  //自定义初始化
void reshape(int w, int h);   //重绘
void display(void);
void keyboardAction(unsigned char key, int x, int y);   //键盘退出事件GLuint vboId;//vertex buffer object句柄
GLuint vaoId;//vertext array object句柄
GLuint programId;//shader program 句柄    int main(int argc, char **argv)
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);glutInitWindowPosition(100, 100);glutInitWindowSize(512, 512);glutCreateWindow("Rectangle demo");//使用glew,需要执行glewInit,不然运行过程会报错//glewInit要放在glut完成了基本的初始化之后执行glewInit();//自定义初始化,生成VAO,VBO对象userInit();//重绘函数glutReshapeFunc(reshape);glutDisplayFunc(display);//注册键盘按键退出事件glutKeyboardFunc(keyboardAction);glutMainLoop();return 0;
}//自定义初始化函数
void userInit()
{glClearColor(0.0, 0.0, 0.0, 0.0);//创建顶点数据    const GLfloat vertices[] = {-0.5f,-0.5f,0.0f,1.0f,0.5f,-0.5f,0.0f,1.0f,0.5f,0.5f,0.0f,1.0f,-0.5f,0.5f,0.0f,1.0f,};//创建VAO对象glGenVertexArrays(1, &vaoId);glBindVertexArray(vaoId);//创建VBO对象   glGenBuffers(1, &vboId);glBindBuffer(GL_ARRAY_BUFFER, vboId);//传入VBO数据glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//解除VBO绑定glBindBuffer(GL_ARRAY_BUFFER, 0);
}//调整窗口大小回调函数
void reshape(int w, int h)
{glViewport(0, 0, (GLsizei)w, (GLsizei)h);
}//绘制回调函数
void display(void)
{glClear(GL_COLOR_BUFFER_BIT);//绑定VBOglBindBuffer(GL_ARRAY_BUFFER, vboId);glEnableVertexAttribArray(0);//解释顶点数据方式glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);//绘制模型glDrawArrays(GL_TRIANGLE_FAN, 0, 4);glBindBuffer(GL_ARRAY_BUFFER, 0);glDisableVertexAttribArray(0);glutSwapBuffers();
}//键盘按键回调函数
void keyboardAction(unsigned char key, int x, int y)
{switch (key){case 033:  // Escape key    exit(EXIT_SUCCESS);break;}
}

例子2:

//使用EBO绘制矩形(两个三角形)
#include <GL/glew.h>
#include <GL/freeglut.h>  void userInit();  //自定义初始化
void reshape(int w, int h);   //重绘
void display(void);
void keyboardAction(unsigned char key, int x, int y);   //键盘退出事件GLuint eboId;//element buffer object句柄
GLuint vboId;//vertext buffer object句柄
GLuint vaoId;//vertext array object句柄    int main(int argc, char **argv)
{glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);glutInitWindowPosition(100, 100);glutInitWindowSize(512, 512);glutCreateWindow("Rectangle demo");//使用glew,需要执行glewInit,不然运行过程会报错//glewInit要放在glut完成了基本的初始化之后执行glewInit();//自定义初始化,生成VAO,VBO,EBOuserInit();//重绘函数glutReshapeFunc(reshape);glutDisplayFunc(display);//注册键盘按键退出事件glutKeyboardFunc(keyboardAction);glutMainLoop();return 0;
}//自定义初始化函数
void userInit()
{glClearColor(0.0, 0.0, 0.0, 0.0);//创建顶点数据    const GLfloat vertices[] = {-0.5f,-0.5f,0.0f,1.0f,0.5f,-0.5f,0.0f,1.0f,0.5f,0.5f,0.0f,1.0f,-0.5f,0.5f,0.0f,1.0f,};// 索引数据GLshort indices[] = {0, 1, 3,  // 第一个三角形1, 2, 3   // 第二个三角形};//创建VAO对象glGenVertexArrays(1, &vaoId);glBindVertexArray(vaoId);//创建VBO对象,把顶点数组复制到一个顶点缓冲中,供OpenGL使用glGenBuffers(1, &vboId);glBindBuffer(GL_ARRAY_BUFFER, vboId);glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//创建EBO对象  glGenBuffers(1, &eboId);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboId);//传入EBO数据glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);//解释顶点数据方式glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);glEnableVertexAttribArray(0);//解绑VAOglBindVertexArray(0);//解绑EBOglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);//解绑VBOglBindBuffer(GL_ARRAY_BUFFER, 0);
}//调整窗口大小回调函数
void reshape(int w, int h)
{glViewport(0, 0, (GLsizei)w, (GLsizei)h);
}//绘制回调函数
void display(void)
{glClear(GL_COLOR_BUFFER_BIT);//绑定VAOglBindVertexArray(vaoId);//绘制模型glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, NULL);glutSwapBuffers();
}//键盘按键回调函数
void keyboardAction(unsigned char key, int x, int y)
{switch (key){case 033:  // Escape key    exit(EXIT_SUCCESS);break;}
}

opengl编程基础篇相关推荐

  1. [内核编程] 内核环境及其特殊性,驱动编程基础篇

    [内核编程] 内核环境及其特殊性,驱动编程基础篇  在学习汉江独钓一书后,打算总结一下内核编程应该注意的事项,以及有关的一些基础知识.第一次接触内核编程,还真是很生疏,很多东西不能一下马上消化.这里做 ...

  2. Python学习之旅(核心编程基础篇003运算符)

    Python学习之旅 Python核心编程基础篇2020.12.18 一.算数运算符 二.比较运算符 三.赋值运算符 四.逻辑运算符 五.成员运算符 六.身份运算符 七.三目运算符 八.运算符优先级 ...

  3. Python编程基础篇

    python编程基础篇之第二节环境搭建和软件安装 文章目录 python编程基础篇之第二节环境搭建和软件安装 前言 一.python介绍 1. python简介 2. python的应用方向 3. p ...

  4. Swift 面向协议编程 基础篇 (一) 介绍

    前言 好久没有写文章了,期末复习周也到了.在复习的同时顺便开了一个专题,面向协议编程,[ 基础篇 ],[ 进阶篇 ],[ 实践篇 ]. 介绍 首先,面向对象(OOP)大家并不陌生,苹果的很多框架都是以 ...

  5. 万物互联之~网络编程基础篇

    入门篇¶ 官方文档:https://docs.python.org/3/library/ipc.html(进程间通信和网络) 实例代码:https://github.com/lotapp/BaseCo ...

  6. java并发编程入门_探讨一下!Java并发编程基础篇一

    Java并发编程想必大家都不陌生,它是实现高并发/高流量的基础,今天我们就来一起学习这方面的内容. 什么是线程?什么是进程?他们之间有什么联系? 简单来说,进程就是程序的一次执行过程,它是系统进行资源 ...

  7. Python Socket编程基础篇

    Socket网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...

  8. 并发编程基础篇——第一章(并发相关基础概念理解)

    其实讲到并发编程,有时候会问自己为什么要去做这些知识的积累和沉淀,可能我们做业务的在职业生涯里,并不会经常使用到这些所谓的多线程编程,顶多可能开一个线程,去执行个任务,又或者通过定时器触发某个业务,实 ...

  9. 【CNC——第6篇】PMAC上位机编程基础篇(上位机和下位机如何通信)

    拓展链接: PAMC官网:DELTA TAU. 官网手册:手册大全 PMAC官网: PCOMM32PRO用户手册 PMAC 的内部变量 内部变量分为四种,I 变量为电机等常用基本控制变量,P 变量为全 ...

最新文章

  1. ABC Perl Programing - 回 2gua 短消息
  2. 面向切面(AOP)之Spring接口方式 schema配置方式 aspectj注解方式
  3. 分支结构||分支循环结构||使用原生js遍历对象
  4. 网络编程套接字(四)
  5. 编程之美3——N!末尾有多少个0
  6. 写一个公用的gpio口驱动
  7. 瑞幸咖啡股价再创新低,App 反冲 TOP 1
  8. React 折腾记 - (4) 侧边栏联动Tabs菜单-增强版(结合Mobx)
  9. rtc校准算法_webrtc aecd算法解析一(原理分析)
  10. [BZOJ2157]旅游(树链剖分/LCT)
  11. 用java编写宠物店管理系统_基于jsp的宠物店管理系统-JavaEE实现宠物店管理系统 - java项目源码...
  12. MCAFEE卸载软件测试初学者,win7系统完全卸载McAfee杀毒软件的两种方法
  13. 自建私有云与公有云托管对比_云托管:利与弊
  14. 如何解决:使用Xbrowser软件连接服务器显示灰屏
  15. 邹城机器人产业园出租_华丰机器人产业园写字楼出租出售租赁出租我们是专
  16. 数字通信中为什么需要时钟线
  17. mysql 双机热备 原理,MySQL双机热备份的配置及原理
  18. python正则表达式入门教程括号及字符
  19. 【PP主数据】工艺路线介绍
  20. 失传万年的PS致富经典(四)

热门文章

  1. Java多线程探究-死锁原因
  2. 计算数据库中各个表的数据量和每行记录所占用空间的脚本-转载来自(博客园 桦仔)...
  3. 【T+】畅捷通T+软件,修改固定资产模块中已经使用卡片的资产编码。
  4. LeetCode/LintCode 题解丨一周爆刷字符串:空格替换
  5. android 隐私文件夹,秘密文件夹 – 隐私保护,隐藏文件夹和文件
  6. [转载]拥抱Jini:从Starter Kit 2.0开始(第二部分)
  7. 相似度算法--莱文斯坦距离加入同义词逻辑
  8. IBM developerWorks 技术主题 Linux 文档库
  9. developerWorks 中国Java technology文档库Spring 系列
  10. LeetCode——缺失数字(C语言)