OpenGL初识

作者: silasjs | 来源:发表于2019-05-30 14:52 被阅读107次

    OpenGL初识

    图形API简介

    • OpenGL(Open Graphics Library):一个跨编程语言、跨平台的图形程序接口,它将计算机的资源抽象称为一个个OpenGL的对象,对这些资源的操作抽象为⼀个个的OpenGL指令。
    • OpenGL ES (OpenGL for Embedded Systems):是OpenGL 三维图形API的子集,针对⼿手机、PDA和游戏主机等嵌⼊式设备而设计,OpenGL ES为了支持新改进的方法抛弃了对于旧式的低效的内存复制操作的支持。
    • DirectX:是由很多API组成的,DirectX并不是一个单纯的图形API。最重要的是DirectX是属于Windows上⼀个多媒体处理API。并不支持Windows以外的平台,所以不是跨平台框架。按照性质分类,可以分为四⼤大部分,显示部分、声⾳部分、输入部分和网络部分。
    • Metal:Apple为游戏开发者推出了了新的平台技术Metal,该技术能够为3D图像提高10倍的渲染性能。Metal是Apple为了解决3D渲染⽽而推出的框架。

    图形API的功能:实现图形的底层渲染

    • 在游戏开发中,对于游戏场景/游戏⼈物的渲染
    • 在⾳音视频开发中,对于视频解码后的数据渲染
    • 在地图引擎,对于地图上的数据渲染
    • 在动画中,实现动画的绘制
    • 在视频处理理中,对于视频加上滤镜效果

    OpenGL名词注解

    • GPU:图形处理单元,图形卡上的可编程芯片,它是高度并行的,并且具有非常快的速度。能够结合几何、颜色、灯光和其他数据而产生一个屏幕图像的硬件组件。

    • 渲染:屏幕只有2维,因此显示3D数据的技巧就在于产生能够迷惑眼睛使其看到丢失的第3维的一个图像。将数学和图形数据转换成3D空间图像的操作叫做渲染

    • 像素:在计算机上显示的图片是由矩形的颜色点组成的,这些矩形的颜色点叫做像素。单独的像素,如果通过放大镜仔细观察显示器,你会看到每个像素都是由3个颜色元素组成的,即一个红点、一个绿点和一个蓝点。

    • 缓存OpenGL ES为两个内存区域间的数据交换定义了缓存(buffers)的概念。缓存是指 图形处理器能够控制和管理的连续RAM。

    程序从 CPU 的内存复制数据到 OpenGL ES 的缓存。在 GPU 取得一个缓存的所有权以后,运行在 CPU 中的程序理想情况下将不 再接触这个缓存。通过控制独占的缓存,GPU 就能够尽可能以最有效的方式读写内存。 图形处理器把它处理大量数据的能力异步同时地应用到缓存上,这意味着在 GPU 使用 缓存中的数据工作的同时,运行在 CPU 中的程序可以继续执行。

    • OpenGL上下文(context):用于配置OpenGL的保存在特定平台的软件数据结构中的信息会被封装到一个OpenGL上下文(context)中。OpenGL是一个状态机器,这意味着在一个程序中设置了一个配置值后,这个值会一直保持,直到程序修改了这个值。切换上下文往往会产生较大的开销,但是不同的绘制模块,可能需要使用完全独立的状态管理。因此,可以在应用程序中分别创建多个不同的上下⽂,在不同线程中使用不同的上下文,上下文之间共享纹理、缓冲区等资源。这样的方案,会⽐反复切换上下文,或者大量修改渲染状态,更加合理高效的。

    • OpenGL状态机

      1. 状态机是一个抽象的模型,表示一组状态变量的集合。每个状态变量可以有各种不同的值,或者只能可以打开或关闭等。当我们在OpenGL中进行绘图时,如果每次都要指定所有这些变量显然有点不切实际。反之,OpenGL使用了一种状态模型(或称状态机)来追踪所有的OpenGL状态变量。当一个状态值被设置之后,它就一直保持这个状态,直到其他函数对它进行修改为止。许多状态只能简单地打开或关闭。例如,深度测试就是要么打开、要么关闭。
      2. OpenGL可以记录自己的状态(比如:当前所使用的颜色、是否开启了混合功能,等等,这些都是要记录的)
      3. OpenGL可以接收输入(当我们调用OpenGL函数的时候,实际上可以看成OpenGL在接收我们的输入),根据输入的内容和自己的状态,修改自己的状态,并且可以得到输出(比如我们调用glColor3f,则OpenGL接收到这个输入后会修改自己的“当前颜色”这个状态;我们调用glRectf,则OpenGL会输出一个矩形)
      4. OpenGL可以进入停止状态,不再接收输入。这个可能在我们的程序中表现得不太明显,不过在程序退出前,OpenGL总会先停止工作的。
    • 顶点(空间中的一个位置):在2D和3D中,当我们绘制一个物体时,实际上是用一些更小的称为图元(Primitives)的形状来组成这个物体。图元是一维或者二维的实体或表面,如点、直线和多边形(平面多边的形状)。在3D空间中,我们把图元组合在一起创建3D物体。例如一个三维立方体是由6个正方形组成,每个正方形代表一个独立的面。正方形(其他任何图元)的每个角称为顶点(Vertex)。这些顶点就在3D空间中指定了一个特定的坐标。顶点其实就是2D或3D空间中的一个坐标。

    • 顶点数组:一个顶点(vertex)就是一个坐标空间的点。顶点数组就是存储这一个图形的所有顶点数据的一段缓存。

    • 管线

      • OpenGL的模型就好比一条生产线或者管线。数据流在这个模型中通常是单一路经的,数据通过我们的程式调用的命令进入管线的开端,然后流过一个一个阶段直到管线的末端。
      • OpenGL通过连接多个叫做着色器的小程序并佐以固定功能函数作为"胶水"来工作。当我们绘图时,图形处理器执行我们的着色器并将它们的输入输出在管线中串联起来,直到像素完成于管线末端。
    • 固定管线/存储着色器

      • 在早期的OpenGL版本,它封装了很多种着色器程序块内置的一段包含了光照、坐标变换、裁剪等等诸多功能的固定shader程序来完成,来帮助开发者来完成图形的渲染而开发者只需要传入相应的参数,就能快速完成图形的渲染。
      • 但是由于OpenGL的使用场景非常丰富,固定管线或存储着色器无法完成每一个业务。这时将相关部分开放成可编程。
    • 着色器程序shader

      • 就全面的将固定渲染管线架构变为了可编程渲染管线。因此,OpenGL在实际调用绘制函数之前,还需要指定一个由shader编译成的着色器程序。常见的着色器主要有顶点着色器(VertexShader),片段着色器(FragmentShader)/像素着色器(PixelShader) ,几何着色器(GeometryShader)曲面细分着色器(TessellationShader)。片段着色器和像素着色器只是在OpenGL和DX中的不同叫法而已。可惜的是,直到OpenGL ES 3.0,依然只支持了顶点着色器和片段着色器这两个最基础的着色器。
      • OpenGl在处理Shader时,和其他编译器一样。通过编译、链接等步骤,生成了着色器程序(glProgram),着色器程序同时包含了顶点着色器和片段着色器的运算逻辑。在0penGL进行绘制的时候,首先由顶点着色器对传入的顶点数据进行运算。再通过图元装配,将顶点转换为图元。然后进行光栅化,将图元这种矢量图形,转换为栅格化数据。最后,将栅格化数据传入片段着色器中进行运算。片段着色器会对栅格化数据中的每一个像素进行运算,并决定像素的颜色。
    • 顶点着色器VertexShader

      • 用来处理图形每个顶点变换(旋转/平移/投影等)。
      • 顶点着色器是逐顶点运算的程序,也就是说每个顶点数据都会执行一次顶点着色器,当然这是并行的,并且顶点着色器运算过程中无法访问其他顶点的数据。
      • 典型的需要计算的顶点属性主要包括顶点坐标变换、逐顶点光照运算等等。顶点坐标由自身坐标系转换到归一化坐标系的运算,就是在这里发生的。
    • 片元着色器程序FragmentShader

      • 用来处理图形中每个像素点颜色的计算和填充的程序。
      • 它是逐像素运算的程序,也就是说每个像素都会执行一次片段着色器,当然也是并行的。
    • GLSL(OpenGL Shadding Language):OpenGL着色器使用一种叫做OpenGL着色语言(OpenGL Shading Language)的语言进行编写,或者叫做GLSL。这个语言的编译器内置在OpenGl中。

    • 光栅化Rasterization:实际绘制或填充每个顶点之间的像素形成线段就叫做光栅化。

    • 纹理:一个用来保存图像的颜色元素值的 OpenGL ES 缓存。

    • 混合Blending:像素的颜色将会和帧缓冲区中颜色附着上的颜色进行混合,混合的算法可以通过0penGL的函数进
      行指定。

    • 变幻矩阵:计算图形发生变化的矩阵。

    • 投影矩阵:用于将3D坐标转换为2D坐标,并在2D下绘制。

    • 渲染上屏/交换缓冲区

      • 一般窗口上显示的是某个渲染缓冲区的资源,如果直接在这个缓冲区中进行渲染,在渲染过程中,窗口会显示不完整的图像。
      • 所以OpenGL程序都至少使用两个缓冲区,在窗口中看到的是屏幕缓冲区,还有一个不显示的离屏幕缓冲区。在离屏缓冲区渲染完成后,通过离屏缓冲区和屏幕缓冲区进行数据交换实现屏幕显示。
      • 屏幕的刷新一般是逐行进行的。如果一次刷新未结束时进行了两个缓冲区交换,图像就会错乱,一部分是旧图的内容,一部分是新图的内容。因此,交换需要等到屏幕发出刷新完成的信号,这个信号叫垂直同步信号,这个技术就是垂直同步技术。
      • 在使用双缓冲区和垂直同步技术的情况下,离屏渲染完成后收到垂直同步信号并交换缓冲区后才能进行下一帧的渲染。这样无法达到最高的帧率,硬件性能产生了浪费。因此,引入了三缓冲区技术。等待垂直同步信号时,交替渲染两个离屏缓冲区,屏幕刷新完成后,屏幕渲染区和最近完成渲染的离屏缓冲区交换。

    OpenGL坐标系解析

    在一个简单的平面计算机屏幕上绘制点和线时,我们根据行和列指定位置。

    在OpenGL或几乎所有的3D PAI中创建一个用于绘制的窗口时,必须指定希望使用的坐标系统以及指定的坐标如何映射到实际的屏幕像素。

    2D笛卡尔坐标系

    在二维绘图中,最常用的是笛卡尔坐标系统。笛卡尔坐标由一个x坐标和y坐标构成。x坐标测量水平方向的位置,y坐标测量垂直方向的位置。x轴和y轴垂直相交定义了一个平面。

    2D笛卡尔坐标系

    3D笛卡尔坐标系

    2D笛卡尔坐标新增一个表示深度分量的z轴就是3D笛卡尔坐标。

    3D笛卡尔坐标系

    视口

    视口就是窗口内部用于绘制裁剪区域的客户区域。视口简单的把裁剪区域映射到窗口中的一个区域。通常,视口被定义为整个窗口,但这并非严格必须的。

    视口被定义为整个窗口

    有时我们只想在窗口的一部分部分进行绘图。我们可以使用视口来缩小和放大窗口中的图像,也可以通过把视口设置大于窗口的用户区域,从而只显示裁剪区域的一部分。

    视口被定义为窗口的一部分

    投影方式

    首先需要理解投影:把3D几何图形的坐标数据投影在一个2D的平面。就像用笔在玻璃上描摹出玻璃后面的物体的外形。而平面上的投影就是视景体。通过指定投影,我们可以指定在窗口中显示的视景体。

    3D图像投影到2D平面

    正投影

    正投影又叫平行投影。使用这种投影时,需要指定一个正方形或长方形的视景体。视景体之外的任何物体都不会被绘制。而且,所有实际大小相同的物体在屏幕上都具有相同的大小,不管它们是远是近。

    正投影

    我们还可以在正投影中通过指定远、近、左、右、顶和底裁剪平面来指定视景体。在这个视景体中出现的物体和图形将被投影( 考虑它们的方向)到一个在屏幕上出现的2D图像。

    透视投影

    在透视投影中,远处的物体看上去比近处的物体更小一些。它的视景体看上去有点像一个顶部被削平的金字塔。剩下来的这个形状称为平截头体( Frustum)。靠近视景体前面的物体看上去比较接近它们的原始大小。但是,当靠近视景体后部的物体被投影到视景体的前部时,它们看上去就显得比较小。在模拟和3D动画中,这种投影能够获得最大程度的逼真感。

    透视投影

    相关文章

      网友评论

        本文标题:OpenGL初识

        本文链接:https://www.haomeiwen.com/subject/dscvtctx.html