学习目录
-
基本介绍
-
基本概念
-
基本流程
-
纹理
-
材质
-
灯光
-
缓冲区
-
帧缓存(FBO)
-
渲染管线:着色器编程
-
高级应用-阴影
-
高级应用-PBR
OpenGL(英语:Open Graphics Library,译名:开放图形库或者“开放式图形库”)是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口(API)。
OpenGL的前身是SGI公司为其图形工作站开发的IRIS GL。IRIS GL是一个工业标准的3D图形软件接口,功能虽然强大但是移植性不好,于是SGI公司便在IRIS GL的基础上开发了OpenGL。
OpenGL规范由1992年成立的OpenGL架构评审委员会(ARB)维护。ARB由一些对创建一个统一的、普遍可用的API特别感兴趣的公司组成。
Khronos Group团队成立于 2000 年 1 月,由包括 3Dlabs, ATI, Discreet, Evans & Sutherland, Intel, Nvidia, SGI 和 Sun Microsystems 在内的多家国际知名多媒体行业领导者创立,致力于发展开放标准的应用程序接口 API ,以实现在多种平台和终端设备上的富媒体创作、加速和回放。
-
(一)发展历程
OpenGL(Open Graphics Library)是一个跨平台的图形API,用于渲染2D和3D图形。自1992年首次发布以来,OpenGL经历了多次重要的版本更新,每个版本都带来了新的功能、性能优化以及更广泛的硬件支持。以下是OpenGL从最初版本到最新版本的发展历程介绍:
1. OpenGL 1.0(1992年)
- 概述:OpenGL 由 SGI(Silicon Graphics, Inc.)在1992年发布,作为用于 3D 图形的硬件抽象层。OpenGL 1.0 是图形编程的一个重大突破,简化了开发人员使用图形硬件的难度。
- 功能:
- 基本的3D图形渲染功能,包括几何图形的绘制、变换、光照、纹理映射等。
- 支持多边形、线条、点等几何体。
- 着重硬件加速的3D渲染功能。
2. OpenGL 1.1(1995年)
- 改进:这是最早广泛采用的版本,增加了多个新功能,成为Windows 95/NT的默认图形库标准。
- 新特性:
- 增加了显示列表的改进,优化了性能。
- 支持纹理对象,大大简化了纹理管理和应用。
- 增强了纹理的性能。
3. OpenGL 1.2(1998年)
- 增强功能:
- 支持 3D 纹理,使得可以在三维体积中进行纹理映射,适用于科学计算可视化等领域。
- 增加了 BGRA 颜色格式,支持更高质量的颜色显示。
- 支持多重纹理单元,能够在一次绘制中使用多个纹理,大大提高了视觉效果的灵活性。
4. OpenGL 1.3(2001年)
- 新功能:
- 提供了多重纹理支持,使得一次绘制调用中可以绑定多个纹理。
- 支持压缩纹理格式(如 S3TC),减少显存占用,提升了渲染性能。
- 支持立方体贴图,用于实现高质量的环境映射(反射、折射效果)。
5. OpenGL 1.4(2002年)
- 改进:
- 增加了对自动生成纹理坐标的支持。
- 改善了深度纹理和阴影映射的支持,优化了光照和阴影效果。
- 增加了 GL_BLEND_COLOR 和 GL_BLEND_EQUATION,用于实现更复杂的混合操作。
6. OpenGL 1.5(2003年)
- 引入 VBO(Vertex Buffer Object):这个版本中引入了 VBO,允许将顶点数据存储在 GPU 上的显存中,大大提升了渲染性能,特别是在绘制大量几何体时。
- 增加了 Occlusion Query:可以检测一个物体是否在当前视图中可见,提升渲染效率。
7. OpenGL 2.0(2004年)
- 着色语言的引入(GLSL):2.0 版本引入了 OpenGL 着色语言(GLSL),允许开发者编写自己的顶点和片段着色器程序,极大地增强了图形编程的灵活性和渲染效果。
- 其他功能:
- 支持非电源的纹理大小,简化了纹理管理。
- 改进了多重采样和浮点纹理。
8. OpenGL 3.0(2008年)
- 重大更新:这是OpenGL自诞生以来的一次重大版本更新,强调了对现代硬件和编程模式的支持。
- 新特性:
- 引入了 VAO(Vertex Array Object),简化了顶点属性管理。
- 增加了浮点缓冲区、全屏抗锯齿、几何着色器的支持。
- 废弃了一些老的、冗余的固定管线功能(如 immediate mode、显示列表等),推动了着色器编程的普及。
9. OpenGL 3.1(2009年)
- 固定管线删除:进一步去除固定功能管线的支持,完全转向基于着色器的编程模型。
- 纹理缓冲对象:支持高效处理和存储大量纹理数据。
- 统一缓冲对象(Uniform Buffer Object):允许在多个着色器之间共享常量数据,提升了数据管理的效率。
10. OpenGL 3.2(2009年)
- 几何着色器增强:允许在 GPU 中生成新的顶点,提高了程序对复杂几何体的处理能力。
- 多重采样纹理:进一步优化抗锯齿功能。
- 引入核心配置文件和兼容性配置文件:将 OpenGL 划分为核心配置(去除了过时功能)和兼容配置(保留了老功能),方便开发者选择合适的编程模式。
11. OpenGL 4.0(2010年)
- 支持 DirectX 11 级别的硬件功能:增强了图形硬件的利用。
- 新特性:
- 增加了曲面细分着色器(Tessellation Shader),允许更精细的模型控制。
- 支持 64 位浮点数精度操作,提高了数值计算的精度。
- 增加了实例化着色器,使得在 GPU 中处理重复对象变得更加高效。
12. OpenGL 4.1(2010年)
- 跨平台兼容性:增强了与 OpenGL ES 2.0 的兼容性,简化了移动设备和桌面设备之间的代码移植。
- 程序管线对象:支持独立的着色器程序对象,开发者可以在不同的着色器阶段使用不同的着色器组合。
13. OpenGL 4.2(2011年)
- 增加的功能:
- 增强了对着色器原子操作的支持,提升了多线程渲染的性能。
- 支持新的纹理格式和压缩技术,提升了纹理处理的灵活性和效率。
- 支持同步原语,使多线程编程更加高效。
14. OpenGL 4.3(2012年)
- 计算着色器(Compute Shader):增加了计算着色器,允许开发者在 GPU 上执行通用计算任务,大大扩展了 OpenGL 的应用场景(如物理模拟、粒子系统、图像处理等)。
- 增加调试输出功能:简化了开发者调试图形应用的流程。
15. OpenGL 4.4(2013年)
- 缓存控制改进:提升了对缓冲对象的控制,使得内存管理更加精细和高效。
- 支持绑定图形存储:改进了对多个图形存储对象的绑定支持。
16. OpenGL 4.5(2014年)
- 与 Direct3D 11 更好的兼容性:提供更好的跨 API 兼容性,允许开发者更轻松地在 OpenGL 和 Direct3D 之间移植应用程序。
- 持久映射缓冲区:允许缓冲区映射在多个帧之间保持有效,减少了 CPU 和 GPU 之间的同步开销。
17. OpenGL 4.6(2017年)
- Vulkan 互操作性:4.6 版本加入了与 Vulkan 的互操作性,使得开发者可以更灵活地在两种 API 之间切换和组合使用。
- SPIR-V 着色器支持:引入了对 SPIR-V 着色器格式的支持,简化了着色器的编译和使用。
- 性能改进:改进了多个 API 的效率,提升了资源加载和处理性能。
总结:
从发展历程上看,OpenGL 1.0~OpenGL 1.5是经典的固定管线时代;OpenGL 2.0~OpenGL 2.1是固定管线和可编程管线并存的时代;OpenGL 3.0~OpenGL 4.x开始是可编程管线崛起的时代。在出现可编程管线的那个时代,OpenGL因为OpenGL ARB的臃肿而一度落后,取而代之的是Khronos Group管理的精简的OpenGL ES流行;最后ARB决定将OpenGL的接力棒交给Khronos Group,在之后的几年内,OpenGL重新焕发了活力,推陈出新至今。另外在移动设备上免授权费用的OpenGL ES的胜利,在一方面上也促进了桌面版的OpenGL重新回到主流地位,现在先进的OpenGL已经受到各个厂家的重视,Nvidia和AMD等显卡制造商都争相发布相关的OpenGL驱动;在游戏开发方面,因为其良好的可移植性,不同的平台、不同的主流引擎都会有OpenGL的实现。
OpenGL 的每一次更新都伴随着对图形硬件功能的利用和编程模型的改进。从最早的固定功能管线,到着色器编程,再到引入计算着色器和与 Vulkan 互操作,OpenGL 不断适应新的硬件和技术需求,同时保持跨平台的优势。随着 OpenGL 4.x 系列的发展,它在高性能图形应用中的地位得到了进一步巩固,并与其他现代图形 API(如 Vulkan)保持协作与竞争。
-
(二)特点及功能
OpenGL 的主要功能:
-
几何体绘制:OpenGL 提供了绘制点、线、三角形、四边形、多边形等基本图元的功能。通过这些基本图元,可以构建出复杂的三维场景和对象。
-
变换和矩阵操作:OpenGL 提供了一套完整的数学库,支持几何体的变换(如平移、旋转、缩放)和投影(如正交投影和透视投影),用于控制对象在3D空间中的位置、方向和大小。
-
光照和阴影:OpenGL 提供了光照计算的基本功能,支持多种光源类型(如点光源、平行光源和聚光灯)以及材质属性定义。通过光照模型,OpenGL 可以模拟真实世界中的光线效果,并生成逼真的阴影效果。
-
纹理映射:纹理映射是 OpenGL 中重要的功能,用于将2D图像(纹理)映射到3D模型的表面上。OpenGL 支持多种纹理格式(如2D纹理、3D纹理、立方体纹理)和纹理滤波模式,可以实现各种复杂的纹理效果,如环境映射、法线贴图、漫反射等。
-
缓冲区管理:其中,**深度缓冲区(Z-buffer)**用于处理物体的遮挡关系,确保场景中的物体按正确的顺序渲染;颜色缓冲区则用于存储最终显示的像素数据。OpenGL 提供了多种缓冲区,如颜色缓冲区、深度缓冲区、模板缓冲区等,用于管理图形渲染过程中不同类型的数据。这些缓冲区的有效管理可以大幅提升渲染的效率和图像质量。
-
着色器编程:从 OpenGL 2.0 开始,引入了 GLSL(OpenGL Shading Language),允许开发者编写自定义的顶点和片段着色器。通过着色器编程,开发者可以完全控制顶点处理、光照计算、纹理应用等图形渲染过程,极大地增强了图形渲染的灵活性和可定制性。
-
多重采样抗锯齿(MSAA):OpenGL 支持多重采样抗锯齿技术,可以减少物体边缘的锯齿效应,提升渲染图像的质量。这对于生成平滑的、高质量的 3D 场景尤为重要。
-
帧缓冲对象(FBO):OpenGL 提供了帧缓冲对象(Framebuffer Object)功能,使得开发者可以将渲染结果输出到纹理或其他缓冲区,而不是直接输出到屏幕。这为后期处理(如屏幕特效、模糊、HDR 等)提供了强大的工具。
-
几何着色器和曲面细分着色器:在 OpenGL 4.x 版本中,引入了几何着色器和曲面细分着色器,允许开发者在 GPU 中生成或修改几何体。这为处理复杂几何结构(如动态生成的草地、树木等)提供了极大的灵活性。
-
计算着色器:OpenGL 4.3 引入了计算着色器功能,允许在 GPU 上执行通用计算任务,不再局限于图形渲染。这使得 OpenGL 可以用于更广泛的应用场景,如物理模拟、粒子系统、大数据处理等。
-
同步与多线程支持:OpenGL 提供了对多线程渲染的支持,并引入了同步原语,允许开发者在多线程环境下安全地处理图形渲染任务。这使得 OpenGL 在多核处理器上更高效。
-
立体3D支持:OpenGL 支持立体渲染,允许开发者为每只眼睛生成不同的视角,以支持虚拟现实和增强现实中的立体显示。
-
(三)OpenGL各扩展库
- 底层库:gl、glu。 gl核心库,115个函数,glu是gl扩展库,43个函数。
- 工具库:aux、glut、freeglut、glfw(主流)提供窗口管理,输入输出,简单的三维图形。
- 自由窗口库:glx、wgl、agl
- Glew:跨平台扩展库,包括所有平台库
- Glad:glew的升级
glut太老了,已经不更新了,但是很多教程还是使用这个。freeglut完全兼容glut,但是依然会有各种bug,glfw轻量级,开源,跨平台,目前主流,取代freeglut。glew跨平台扩展库,包括所有平台库。Glad,可以看作是glew的升级。
各库介绍如下:
1. GL (OpenGL核心库)
115个基本函数,以“gl”为前缀,函数用于常规的、核心的图形处理,如建立各种几何模型,产生光照效果,进行反走样及投影变化等。
分类 | 举例 |
绘制基本几何图元 | glBegain()、glEnd()、glNormal*()、glVertex*() |
矩阵操作、几何变换和投影变换 | 矩阵入栈函数glPushMatrix()、矩阵出栈 函数glPopMatrix()、装载矩阵函数glLoadMatrix()、矩阵相乘函数glMultMatrix(),当前矩阵函数glMatrixMode()和矩阵标准化函数glLoadIdentity(),几何变换函数glTranslate*()、glRotate*()和glScale*(),投影变换函数glOrtho()、glFrustum()和视口变换函数glViewport() |
颜色、光照和材质 | 颜色模式函数glColor*()、glIndex*(),光照效果的函数glLight*() 、glLightModel*()和材质效果函数glMaterial() |
显示列表 | 创建、结束、生成、删除和调用显示列表的函数glNewList()、 glEndList()、glGenLists()、glCallList()和glDeleteLists() |
纹理映射 | 一维纹理函数glTexImage1D()、二维纹理函数glTexImage2D()、 设置纹理参数glTexParameter*()、纹理环境glTexEnv*()和纹理坐标的函数glTetCoord*() |
特殊效果 | 融合函数glBlendFunc()、反走样函数glHint()和雾化效果glFog*() |
光栅化、象素操作 | 象素位置glRasterPos*()、线型宽度glLineWidth()、多边形绘制模式glPolygonMode(),读取象素glReadPixel()、复制象素glCopyPixel() |
选择与反馈 | 渲染模式glRenderMode()、选择缓冲区glSelectBuffer()和反馈缓冲区glFeedbackBuffer() |
曲线与曲面的绘制 | 生成曲线或曲面的函数glMap*()、glMapGrid*(),求值器的函数glEvalCoord*() glEvalMesh*() |
状态设置与查询 | glGet*()、glEnable()、glGetError() |
2.GLU (OpenGL Utilities,OpenGL实用库)
包含有43个函数,函数名的前缀为glu。为了减轻繁重的编程⼯作,封装了OpenGL函数,Glu函数通过调⽤核⼼库的函数,为开发者提供相对简单的⽤法,实现⼀些较为复杂的操作,如纹理映射、坐标变化、网格化、曲线曲面绘制以及二次物体(圆柱、球体)绘制等。 主要包括了以下几种:
分类 | 举例 |
辅助纹理贴图 | gluScaleImage() 、gluBuild1Dmipmaps()、gluBuild2Dmipmaps() |
坐标转换和投影变换 | 定义投影方式函数gluPerspective()、gluOrtho2D() 、gluLookAt(),拾取投影视景体函数gluPickMatrix(),投影矩阵计算gluProject()和 gluUnProject() |
多边形镶嵌工具 | gluNewTess()、 gluDeleteTess()、gluTessCallback()、gluBeginPolygon() gluTessVertex()、gluNextContour()、gluEndPolygon() |
二次曲面绘制工具 | 绘制球面、锥面、柱面、圆环面gluNewQuadric()、gluSphere()、gluCylinder()、gluDisk()、gluPartialDisk()、gluDeleteQuadric() |
非均匀有理B样条绘制工具 | 定义和绘制Nurbs曲线和曲面,包括gluNewNurbsRenderer()、gluNurbsCurve()、gluBeginSurface()、gluEndSurface()、gluBeginCurve()、gluNurbsProperty() |
错误反馈工具 | 获取出错信息的字符串gluErrorString() |
3. Glaux(OpenGL辅助库)
GLAUX(OpenGL辅助库)所使⽤用的函数和常量量声明。
这个库的功能⼤大致与<GL/glut.h>类似,这个库提供了了创建窗⼝口,处理理键盘和⿏鼠标事件,设置调⾊色板等OpenGL本身不不提供,但在编写OpenGL程序时⼜又经常⽤用到的功能。⽬目前这个库已经过时,只有比较少的编译环境中有提供,例如VC系列。在VC系列列编译器器中,使⽤用这个头⽂文件之前必须使用#include或者具有类似功能的头⽂文件。
31个函数,以“aux”为前缀,主要用于窗口管理、输入/输出处理以及绘制简单三锥形体,并不能在所有的OpenGL平台上使用,主要包括了以下几种[2]:
分类 | 举例 |
窗口初始化和退出函数 | auxInitDisplayMode()和auxInitPosition() |
窗口处理和时间输入函数 | auxReshapeFunc()、auxKeyFunc()和auxMouseFunc() |
颜色索引装入函数 | auxSetOneColor() |
三维物体绘制函数 | 两种形式网状体和实心体,如绘制立方体auxWireCube()和 auxSolidCube()。以网状体为例,长方体auxWireBox()、环形圆纹面auxWireTorus()、圆柱auxWireCylinder()、二十面体auxWireIcosahedron()、八面体auxWireOctahedron()、四面体auxWireTetrahedron()、十二面体auxWireDodecahedron()、圆锥体auxWireCone()和茶壶auxWireTeapot() |
4. GLUT (OpenGL Utility Toolkit,实用工具库,被淘汰)
30多个函数,以“glut”为前缀,提供基于窗口的工具。 如:窗口的初试化、多窗口管理、菜单管理、字体以及较复杂物体的绘制,主要包括了以下几种
分类 | 举例 |
窗口操作 | 窗口初始化、窗口大小、窗口位置等函数glutInit() glutInitDisplayMode() glutInitWindowSize() glutInitWindowPosition() |
回调函数 | 响应刷新消息、键盘消息、鼠标消息、定时器函数等,GlutDisplayFunc() glutPostRedisplay() glutReshapeFunc() glutTimerFunc() glutKeyboardFunc() glutMouseFunc() |
创建复杂的三维物体 | 创建网状体和实心体。如glutSolidSphere()、glutWireSphere() |
菜单函数 | 创建添加菜单的函数GlutCreateMenu()、glutSetMenu()、glutAddMenuEntry()、glutAddSubMenu() 和glutAttachMenu() |
程序运行函数 | glutMainLoop() |
5.Freeglut
Freeglut 是一个开源的图形工具库,专门用于创建 OpenGL 应用程序的窗口和处理输入事件。它是著名的 GLUT(OpenGL Utility Toolkit)的一个改进和兼容版本,目的是克服 GLUT 库开发不再更新的局限性。
Freeglut 的主要功能:
- 窗口管理:支持创建、销毁和管理多个窗口,可以设置窗口大小、标题和位置。
- 事件处理:处理键盘、鼠标、窗口调整、菜单等事件,方便用户与应用程序进行交互。
- 与 OpenGL 的集成:能够方便地集成 OpenGL 渲染,使得程序员能够轻松创建交互式的 3D 图形应用程序。
- 跨平台:Freeglut 支持 Windows、Linux 和 macOS 等多个操作系统,具有良好的移植性。
- 菜单支持:提供简单的菜单系统,能够创建上下文菜单。
6. Glfw库
允许我们创建一个OpenGL上下文,定义窗口参数和处理所有我们需要的用户输入,以“glfw”为前缀。GLFW一个轻量级的,开源的,跨平台的library。支持OpenGL及OpenGL ES,用来管理窗口,读取输入,处理事件等。因为OpenGL没有窗口管理的功能,所以很多热心的人写了工具来支持这些功能,比如早期的glut,现在的freeglut等。那么GLFW有何优势呢?glut太老了,最后一个版本还是90年代的。freeglut完全兼容glut,算是glut的代替品,功能齐全,但是bug太多。稳定性也不好(不是我说的啊),GLFW应运而生。
7. GLEW
glew是一个跨平台的C++扩展库,基于OpenGL图形接口。要使⽤OpenGL的高级特性,就必须下载最新的扩展,另外,不同的显卡公司,也会发布一些只有⾃自家显卡才⽀支持的扩展函数,你要想⽤用这数涵数,不得不去寻找最新的glext.h,有了了GLEW扩展库,你就再也不不⽤用为找不不到函数的接⼝口⽽而烦恼,因为GLEW能自动识别你的平台所⽀支持的全部OpenGL⾼高级扩展涵数。也就是说,只要包含⼀一个glew.h头⽂文件,你就能使用gl,glu,glext,wgl,glx的全部函数。GLEW⽀支持目前流⾏的各种操作系统(including Windows, Linux, Mac OS X, FreeBSD, Irix, and Solaris)
8. Glad
GLAD(OpenGL Loader Generator)是一个用于生成 OpenGL 函数加载器的工具库,帮助开发者更方便地管理和调用 OpenGL API。由于 OpenGL 的函数在不同的硬件平台和操作系统上可能不一致,GLAD 提供了一种标准化的方法来动态加载 OpenGL 函数指针。
GLAD 的主要特点:
- 动态加载 OpenGL 函数:OpenGL 的函数需要在运行时从系统库加载,GLAD 生成的加载器能够确保这些函数在调用前被正确加载。
- 支持多种图形 API:GLAD 不仅支持 OpenGL,还支持 OpenGL ES、Vulkan 和 WGL、GLX 等平台扩展,适用于不同的图形开发场景。
- 跨平台:GLAD 生成的代码可以在不同操作系统上运行,包括 Windows、Linux 和 macOS,提供跨平台的兼容性。
- 基于需求定制:GLAD 提供了在线生成器,开发者可以根据自己的项目需求选择 OpenGL 的特定版本、扩展和 API,生成最适合项目的加载器代码。
- 自动化:GLAD 能够解析 OpenGL 的规范,自动生成与选定版本兼容的加载器,避免了手动处理 OpenGL 扩展的复杂性。
GLAD 的工作原理:
- GLAD 从 OpenGL 的官方 XML 规范文件中解析出不同版本的函数和扩展。
- 根据用户选择的 OpenGL 版本和扩展,GLAD 自动生成适配这些 API 的加载代码。
- 在运行时,GLAD 通过底层平台(如 Windows 的 WGL,Linux 的 GLX)动态加载 OpenGL 函数指针,确保 OpenGL 的函数可用。
9.各平台自由窗口库
OpenGL被设计为只有输出的,所以它只提供渲染功能。核心API没有窗口系统、音频、打印、键盘/鼠标或其它输入设备的概念。虽然这一开始看起来像是一种限制,但它允许进行渲染的代码完全独立于他运行的操作系统,允许跨平台开发。然而,有些整合于原生窗口系统的东西需要允许和宿主系统交互。
(1)wgl-Window专用库
wgl–Window专用库:16个函数,用于连接OpenGL和WindowsNT[2].
分类 | 具体 |
绘图上下文相关函数 | wglCreateContext(), wglDeleteContext()wglGetCurrentContent() wglGetCurrentDC() wglDeleteContent() |
文字和文本处理函数 | wglUseFontBitmaps()、wglUseFontOutlines() |
覆盖层、地层和主平面层处理函数 | wglCopyContext()、wglCreateLayerPlane()、 wglDescribeLayerPlane()、wglReakizeLayerPlatte() |
其他函数 | wglShareLists()、wglGetProcAddress() |
(2) glx:(OpenGL Extension to the X Window System)
它作为x的扩展,是x协议和X server的⼀一部分,已经包含在X server的代码中了了。GLX提供了了x window system使⽤用的OpenGL接⼝口,允许通过x调⽤用OpenGL库。OpenGL 在使⽤用时,需要与⼀一个实际的窗⼝口系统关联起来。在不不同平台上有不不同的机制以关联窗⼝口系统,在Windows上是WGL,在Linux上是GLX,在Apple OS上是AGL等。