OpenGL 系列

3654 Views

前置知识科普部分对相关概念一带而过。但对新同学至关重要 – 避免在庞杂的书面知识上浪费时间。技术选型部分对相关技术仅给出当前考量 – 方向是对的,剩下的就是工作量。技术细节部分对相关技术细节的设计作详细阐述 – 浪费您的时间了。

知识科普本文提及渲染时,统一默认为 OpenGL(或OpenGL ES) 和它的 GLSL。同时,文中尽量减少不必要的专业名词或术语。

什么是 OpenGL?请从状态机的角度,去理解它。请从客户机/服务器的角度,去理解它。

什么是 OpenGL?如果从 OpenGL 以什么方式完成什么事情的角度,更愿意把它看作一个“建模大师” –(拿来用而已)

颜色提及 RGB, 大多数人习以为常。提及 BGR,OpenCV开发人员比较熟悉(默认颜色空间)。至于其他的颜色空间,也只是表示方式不同。颜色处理时,99%的情况要转为 RGB 三成分。数据传输时,按需转为其他格式。

在解码时,要输出哪种格式?这是数据源要关注的点。如果从渲染的角度判断,那就是:当前显卡驱动支持的最优格式。

对于渲染链路中的数据,要注意什么?

尽量保持数据大小和数据格式不变,以减少格式转换带来的额外开销。

尽量通过代码设计避免数据copy,以减少不必要的开销。

尽量拥抱新知识,将耗时操作从 CPU 转移到 GPU。

光照基础领域的研究成果,拿来用用而已(模拟现实是VR,增强现实是AR等)

对光源的划分光源划分本身就是一个建模的过程。比如:太阳光定义为平行光;白炽灯定义为点光源。

对光源成分的划分同样是一个建模的过程,比如:环境光,漫反射,高光反射等。

对光源成分建模一堆计算公式而已,比如:Lambert模型, Half-Lambert模型, Phong模型,Blinne-Phong模型。建议忽略该部分,这是 TA 操心的事情。

坐标系无论是一场 AR 直播,一个复杂的游戏场景,或者一幅图片,在生动的视觉效果背后都存在一个摸不着的虚拟世界。虚拟世界的完整描述,依赖各类坐标系(左右手):世界坐标系,模型坐标系,观察坐标系,裁剪坐标系。借助这些信息,渲染流水线得以完成各种变换(MVP)。

世界坐标系描述了所有模型和光源位置

光照计算需要在模型坐标系下进行

视图坐标系定义了相机的位姿,直接影响画面的输出

裁剪坐标系是经过透视除法后的坐标系,设计正交投影和透视投影。其中,透视投影矩阵是对近大远小等透视效果的建模。

模型对人物或物体的建模,本质上就是描述其轮廓/包络/网格的过程。下面对一个模型文件进行分析:

准备环节通过资源网站下载或者 blender 生成模型文件。为避免展开话题,我们限定模型文件格式为 .obj。

格式定义mtllib 部分:忽略该部分(包含各种反射的参数信息,纹理文件信息等内容)object 部分:必备参数(:v, :f),可选参数(:vt, :vn)。

必备参数:顶点:v 和三角面:f 完整描述了物体的包络/网格。

可选参数:忽略该部分(纹理顶点:vt 描述了贴图的映射信息,顶点法线:vn 用于光照计算)

应用分析必备参数完整描述了模型的包络信息。可选参数算是辅助信息,比如:顶点法线用于光照计算(可在导入引擎时生成);纹理顶点相当于物体/人物贴图映射关系等等。

对于 OpenGL 开发来说,控制如何绘制顶点是比较重要的一环。比如:

需要初始化 VBO 信息,也即顶点:v

需要初始化 EBO 信息,也即顶点索引:f

可能需要初始化 VAO,也即元数据。它描述各个 buffer 的数据存储信息(VBO,EBO)

可能需要初始化 PBO,用于释放 glTextureSubImage2D 操作的 cpu 占用

对于引擎应用开发来说,更多的工作集中在 shader 及 shader 参数配置

什么是 OpenGL?请忘掉上述回复。对于常规 opengl 开发,它跟普通的库没有区别。只需要了解相关接口即可。

非必要,不要引入 MVP。比如:视频帧渲染,如果默认 MVP 都是单位阵,试试有什么效果?

非必要,不要接触光照,那是 TA 操心的内容。再者,视频帧渲染跟光照没有半毛钱关系。

没必要接触模型。对于视频帧或者图片渲染来说,模型就是四个顶点(两个三角面/一个四边面)。

技术选型QT 技术栈qt quick不存在渲染性能问题,qt quick 默认采用 gpu 渲染。在禁用 gpu (qt::aa_usesoftwareopengl)的情况下,才会 fallback。

qt qwidgetqwidget 是采用 cpu 渲染。如果想利用 gpu 的优势,需要借助 qopenglwidget 控件,并且需要大量的工作

oepngl 版本控制: 兼容用户的显卡驱动版本

pbo 技术: gles 4.2, opengl 3.3 才得以支持

gl_polygon 枚举:旧版本的参数在新版本已被舍弃

shader 指令: gles 中 inout 参数需要提供精度信息

fallback 操作:对于禁用 gpu 的场景,需要额外提供软渲作为兜底

opengl 渲染:需要同时支持 opengl 和 gles

软渲:用于 fallback 场景

QT 渲染属性qt::aa_usedefault (qt 没有该枚举,用于占位)默认情况下, qt 会渲染当前显卡驱动的 opengl 版本,比如:4.6

qt::aa_useopengles当指定该渲染属性时,qt 会选择显卡驱动支持的 gles 版本,比如:2.0

qt::aa_usesoftwareopengl当指定该渲染属性时,当前应用中的所有 ui 渲染都会 fallback

QT 渲染方式paintevent(*) with qpainterqwidget 提供的渲染接口,也即上文的软渲。由于 qopenglwidget 是继承至 qwidget,所以需要实现该接口用于 fallback 场景

paintgl() with qpainter提供了灵活支持,可以使用一些非 opengl 指令。但该操作本身会占用 cpu

paintgl() with opengl commands即是 opengl 渲染~

OpenGL & Shaderopengl 与着色器 shader 是什么关系呢?对于 opengl 来说,glsl 算是一个辅助工具。借用《红宝书第七版》的描述: glsl 可以进一步发掘 OpenGL 的现代硬件实现的计算威力。 如果没有shader, 某些计算只能在 cpu 中进行。

不使用 shader, opengl 可以完成常规渲染操作吗?对于引擎应用开发来说,不行。引擎应用开发唯一能操作的就是shader,他们无需关心 opengl 底层接口。对于非引擎应用开发,shader 是一个可选项。多重纹理渲染那的场景:

当纹理大小完全匹配时,单次 draw call 即可完成

当纹理大小不完全匹配且某些纹理需要等比缩放(cover 模式)

opengl 实现: 使用独立的顶点和纹理映射,多次 draw call 即可完成(配合 blend separate)

shader 实现: 多次 draw call 比较麻烦;单次 draw call 时,需要借助 cpu 完成对各个纹理进行缩放和平移

注:draw call 是引擎渲染中的术语。对于 opengl 开发,就是一次顶点接口调用,如:glDrawElements。

阅读推荐《OpenGL 红宝书第七版》:建议精读。后续接触新知识时,会更容易理解它们的由来。《OpenGL 红宝书第九版》:大部分内容趋于同质化。只需了解最新的纹理及多重纹理内容即可。《OpenGL ES 3.0 编程指南》:工具书,方便查询接口。

技术细节截至前两部分,本文基本上已经完成。代码是廉价的,偷懒不想再作详细介绍~~ bye

1282 error: 参数错误。 opengl 不同版本会舍弃一些参数;

1281 error: 接口报错,比如:pbo 映射内存时,没有进行 bind 操作;

glteximage 接口:比较耗时哦。尽量合理利用;

ffmpeg 解码:尽量借助帧间隔(sleep)完成对一阵纹理的提交,避免多余的内存 copy。

如何在Windows上恢复已删除文件夹(2025教程)
小红书无物流发货怎么设置?小红书不发货只赔3元怎么办