《视觉开发专题》之 OpenGL 概述

栏目: 后端 · 发布时间: 5年前

内容简介:这是这几个小模块来一一介绍,阅读完本篇内容你将收获:友情提示:该篇文字较多,比较适合对 OpenGL 知之甚少的同学阅读,已经有相关经验的大佬可以溜了:stuck_out_tongue_closed_eyes:,闲言少叙,直入正题。

这是 视觉专题 的第一篇,将分为:

  1. 什么是 OpenGL
  2. OpenGL 语法说明
  3. OpenGL 渲染管线
  4. OpenGL 程序&渲染流程分析

这几个小模块来一一介绍,阅读完本篇内容你将收获:

  1. OpenGL 是什么
  2. OpenGL 渲染管线的工作流程

友情提示:该篇文字较多,比较适合对 OpenGL 知之甚少的同学阅读,已经有相关经验的大佬可以溜了:stuck_out_tongue_closed_eyes:,闲言少叙,直入正题。

注: 该专题默认使用 核心模式 来进行,需要 OpenGL 的版本在3.3以上。

一:什么是 OpenGL

一般它被认为是一个 API (Application Programming Interface, 应用程序编程接口),包含了一系列可以操作图形、图像的函数(通过直接访问图形硬件设备的特性来实现)。事实上,OpenGL 本身并不是一个API,它仅仅是一个由 Khronos 组织制定并维护的规范(Specification)。

OpenGL 规范严格规定了每个函数该如何执行,以及它们的输出值。至于内部具体每个函数是如何实现(Implement)的,将由 OpenGL 库的开发者自行决定(这里开发者通常是显卡的生产商)。

因为 OpenGL 规范并没有规定实现的细节,具体的 OpenGL 库允许使用不同的实现,只要其功能和结果与规范相匹配即可。所以,当你使用 Apple 系统的时候,OpenGL 库是由 Apple 自身维护的。在 Linux 下,有显卡生产商提供的 OpenGL 库,也有一些爱好者改编的版本。这也意味着任何时候 OpenGL 库表现的行为与规范规定的不一致时,基本都是库的开发者留下的bug。

OpenGL 是使用客户端 - 服务端的形式实现的,我们编写的应用程序可以看做客户端,而计算机图形硬件厂商所提供的 OpenGL 实现可以看做服务端。我们编写的 OpenGL 命令,最终会被转换为相关的协议提交给服务端,然后被执行并产生图像内容。

二:OpenGL 语法

OpenGL 库中所有的函数都会以字符“gl”作为前缀,然后是个或多个大写字母开头的词组,以此来命名一个完成的函数(如 glBinVertexArray() )。除此之外你还会看到“glfw”开头的函数,它们来自第三方库GLFW,这是一个抽象化窗口管理和其他系统任务的开发库。类似的,还有“gl3w”开头的函数,它们来自三方库 GL3W 。后续会进一步展开讲这两个库的内容。

与函数命名约定类似,OpenGL 库中定义的常量采用“GL_”开头,通过 #define 来完成常量的定义。为了方便在不同的操作系统之间移植 OpenGL 程序,OpenGL 还为函数定义了不同的数据类型,如 GLfloat ,所以最好统一使用 OpenGL 定义的数据类型,这样就不需要关心系统兼容性问题了。

由于 OpenGL 是一个 C 语言形式的库,因此它不能使用函数的重载来处理不同类型的数据,它通过函数名称的细微变化来实现同一类功能函数集的管理。举个例子: glUniform2f()glUniform3fv() ,前者的后缀 2f 表示这个函数需要两个 GLfloat 类型的参数(以此类推,目前一共定义了24种不同的 glUniform* ()函数),后者的后缀多出的一个 v 是 vector 的缩写,即表示它需要传入一个包含三个 GLfloat 类型元素的一维数组作为参数。

所有可以作为后缀的字母,以及它们所对应的数据类型:

《视觉开发专题》之 OpenGL 概述

三:OpenGL 渲染管线

早期的(3.3版本以前) OpenGL 使用 立即渲染模式 (Immediate mode,即固定渲染管线):OpenGL的大多数功能都被库隐藏起来,开发者很少能控制 OpenGL 计算的过程。固定渲染管线较容易使用和理解,但是效率太低且不够灵活。

当使用OpenGL的核心模式时,OpenGL 迫使我们使用现代的函数,现代函数具有更高的灵活性和效率性,也能让人更容易清楚 OpenGL 是如何运作的,更好的理解图形编程。但入门门槛也稍有增加。

我们通常所说的 渲染管线 (rendering pipeline),它包含了两个部分:第一部分把你的3D坐标转换为2D坐标,第二部分是把2D坐标转变为实际的有颜色的像素。下图是 OpenGL4.5 版本的 管线 示意图:

《视觉开发专题》之 OpenGL 概述
OpenGL 首先接收用户提供的几何数据(顶点和几何图元),并且将它输入到一系列着色器阶段中进行处理,然后将处理后的数据送入光栅化单元(rasterizer)。光栅化单元负责对所有剪切区域内的图元生成片元数据,我们可以将一个片元视为一个“候选的像素”,然后对每个生成的片元都执行一个片元着色器,这一步会计算出这个片元的最终颜色。注意,即使在片元着色器中计算出来了一个像素输出的颜色,在渲染多个三角形的时候最后的像素颜色也可能完全不同,还会受 深度混合

的影响,这个后面会详细讲。

我们可以通过控制我们需要的着色器来实现自己所需的功能,事实上,只有顶点着色器和片元着色器是必需的,细分和几何是可选的步骤。为了更好理解顶点着色器和片元着色器的分工和区别,可以总结为: 顶点着色(包括细分和几何着色)决定了一个图元应该位于屏幕的什么位置,而片元着色使用这些信息来决定某个片元的颜色应该是什么

五:OpenGL 程序&渲染流程分析

无论 OpenGL 的程序写的有多么庞大与复杂,它的基本结构通常都是类似的:

  1. 初始化物体渲染所对应的状态。
  2. 设置需要渲染的物体。

在上代码之前,咱们需要对必要的图形学名词有基本的理解。

  • 渲染 :计算机从模型到最终的图像创建的过程。OpenGL 只是计算机渲染系统的其中一种,基于光栅化的系统。 Object,IBO. 决定了绘制顶点的顺序,避免顶点数据重复造成的资源浪费。
  • OpenGL 状态机 :可以看做一个上下文(context),在调用任何 OpenGL 的指令之前,都需要先创建并进入这样的上下文中,它可以记录自己当前的状态,并能接收新的输入(调用 OpenGL 函数),当关闭了上下文,就不再接收输入。
  • 着色器 (Shader) :为 图形渲染管线 中的某个特定部分,将输入转化为输出的程序。在 OpenGL 中,会涉及到六种不同的着色阶段,其中最常用的包括 顶点着色器 以及 片元着色器 ,前者用于处理顶点数据,后者用于处理光栅化后的片元数据。着色器运行在 GPU 上,在 OpenGL 使用它之前,必须经过编译并链接为一个 着色器程序对象 (Shader Program Object)。

一个简单顶点着色器的源代码长这样:

void main(){
    gl_Position = ftransform();
}
复制代码

一个简单片元着色器的源代码:

void main() {
    gl_FragColor = vec4(1.0,0.5,0.2,1.0);
}
复制代码

它们都需要用GLSL (OpenGL Shading Language,着色器语言) 。

  • 标准化设备坐标(Normalized Device Coordinates, NDC):一旦你的顶点坐标已经在顶点着色器中处理过,它们就应该是标准化设备坐标了,标准化设备坐标是一个x、y和z值在-1.0到1.0的一小段空间。任何落在范围外的坐标都会被丢弃/裁剪,不会显示在你的屏幕上。

  • 像素:显示器上最小的可见单元。

  • 帧缓存:保存着所有计算机生成的图像的像素点,它是由图形硬件设备管理的一块独立内存区域,可以直接映射到最终的显示设备上。

  • 顶点缓冲对象:Vertex Buffer Object, VBO . 管理着在GPU内存(通常被称为显存)中,一块储存着大量顶点数据的内存。因为从CPU把数据发送到显卡相对较慢,所以只要可能我们都要尝试尽量一次性发送尽可能多的数据。

  • 顶点数组对象:Vertex Array Object, VAO . 可以像顶点缓冲对象那样被绑定,任何随后的顶点属性调用都会储存在这个 VAO 中。这样的好处就是,当配置顶点属性指针时,你只需要将那些调用执行一次,之后再绘制物体的时候只需要绑定相应的 VAO 就行了。这使在不同顶点数据和属性配置之间切换变得非常简单。

    《视觉开发专题》之 OpenGL 概述
    当你打算绘制多个物体时,你首先要生成/配置所有的VAO(和必须的VBO及属性指针),然后储存它们供后面使用。当我们打算绘制物体的时候就拿出相应的VAO,绑定它,绘制完物体后,再解绑VAO。
  • 索引缓冲对象:Element Buffer Object,EBO或Index Buffer. 专门储存顶点绘制的索引,OpenGL调用这些顶点的索引来决定该绘制哪个顶点。由于三角形是绘制的基本图形,对于一些复杂图形会存在很多三角形(共用边)的顶点重合问题,该索引就是为了解决此问题,从而降低开销。

我写了一份简单的 OpenGL 示例程序 给你作参考,附有比较详细的渲染流程分析,需要的同学自取,这里就不占篇幅粘代码了。用 Xcode 打开程序直接 Run, 就可以看到该效果:

《视觉开发专题》之 OpenGL 概述

这份 Demo 使用了可编程渲染管线,自定义了简单的着色器,初学者不需要搞清楚每一步的原理,先对 OpenGL 的语法和基本结构有个初步的了解就行。

总结

枯燥的概念和晦涩的专业术语很容易让初学者望而生畏,所以此篇我只选了一些必要的概念,做了简要的介绍。建议结合文中提供的源码,把上面涉及到的步骤一一拆解,进而加深对相关概念以及 OpenGL 工作流程的理解。

近来因工作和身体原因,文章更新滞后了两周有余,现已恢复正常。

下一篇文章将使用 固定管线 来完成一些动画效果,顺带介绍涉及到的 OpenGL 知识,这样更好理解。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

理想主义者

理想主义者

[美] 贾斯汀·彼得斯 / 程静、柳筠 / 重庆出版社 / 2018-5-15 / 49.80元

2013年1月11日,年仅26岁的黑客亚伦·斯沃茨自杀身亡,此事在美国引起轩然大波。这不仅是因为在互联网领域,斯沃茨是一个可以与比尔·盖茨、马克·扎克伯格、理查德·斯托曼等齐名的人,更是因为此事揭露了传统世界与互联网世界的规则冲突。 在互联网思维下,信息是明码标价的商品。各种利益方用技术竖起了一道道藩篱,将支付不起费用但渴望用知识改变命运的人隔绝在外。于是,一大批希望改变这种模式的“理想主义......一起来看看 《理想主义者》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具