0%

opengl简介

OpenGL简介(What is OpenGL)

OpenGL是一个提供操作图形和图像的API标准(注意是标准,而不是实际的某种编程语言的接口),这些接口标准由Khronos Group管理。OpenGL接口标准定义每个函数的输入输出是什么,每个函数应该有怎样的表现等等。这些接口最终由开发者来实际实现(一般是显卡厂商)。虽然不同开发者实现的Open GL的代码细节不同,但是由于标准的存在,对于用户来说使用方式和最终结果是没有区别的(如果有,那就是显卡制造商写的OpenGL实现有问题)。

Core Profile模式和Immdiate 模式

在以前,使用OpenGL开发用的是immdiate模式,immediate模式是指固定的渲染管线,用户只需要开发少量的代码,就能获得最终的渲染图形,但是同时,用户对渲染过程的控制度很低,在处理渲染上灵活性很差。从OpenGL 3.2开始,OpenGL开始使用core-profile模式,从3.2版本开始,这是OpenGL的一个分支,这个版本删除了所有旧的不推荐使用的功能。当我们在core-profile模式下,OpenGL会强迫我们使用现代的渲染方法,当我们尝试使用已经Deprecated的方法时,OpenGL会抛出异常并停止渲染。

OpenGL扩展(Extensions)

OpenGL一个很好的特性就是扩展,当显卡公司对于渲染有了新的优化或者有新的渲染技术,这些就可以通过扩展的形式发布出去给用户使用,而不用等OpenGL把这些功能新加入到OpenGL标准中,对于用户而言,在编写OpenGL程序的时候只需要判断是否有相应扩展,如果有就可以使用相应的接口。

1
2
3
4
5
6
7
8
if(GL_ARB_extension_name)
{
// Do cool new and modern stuff supported by hardware
}
else
{
// Extension not supported: do it the old way
}

状态机

OpenGL标准本身可以看作是一个状态机的定义:定义当前OpenGL应该如果运行的变量集合。OpenGL的状态同城称为OpenGL context,在使用OpenGL时,我们经常通过设置一些选项、操作一些缓冲区然后对当前上下文进行渲染来更改其状态。

GLAD

OpenGL 实际上只是一个标准/规范,由驱动程序制造商将规范实现到特定显卡支持的驱动程序。由于OpenGL驱动有很多不同的版本,其大部分函数的位置在编译时是未知的,需要在运行时查询。然后开发人员的任务是检索需要的函数的位置并将它们存储在函数指针中供以后使用,这个步骤可以通过GLAD这个库来帮助实现。

渲染管线

在OpenGL中,所有的都是3维空间,但是屏幕石油二维的像素组成的,所以OpenGL大多数的工作其实就是将3维空间的坐标转换到二维空间的像素,这个过程就是有渲染管线来完成的。渲染管线可以分为两大部分:第一部分,将3D坐标转换为2D坐标;第二部分将2D坐标转换为具体的颜色像素。

渲染管线的具体步骤可以分为多步,每一步都需要将前一步的输出作为自己的输入,并且每一步都是高度可定制化的,而且可以很方便的并行处理。由于并行化的特性,现代图形卡可以快速处理渲染管线中的步骤。

Because of their parallel nature, graphics cards of today have thousands of small processing cores to quickly process your data within the graphics pipeline. The processing cores run small programs on the GPU for each step of the pipeline. These small programs are called shaders.

vertex shader

vertex shader将单个vertex作为输入,单个vertex作为输出。vertex shader的主要作用是将3D坐标转换为另外一个3D坐标,并对vertex的属性做一些额外的处理。

primitive assembly

primitive assembly步骤将vertex shader的所有输出作为输入,以此来形成primitive shape,primitive shape是组成最终物体的基础形状。

In order for OpenGL to know what to make of your collection of coordinates and color values OpenGL requires you to hint what kind of render types you want to form with the data. Do we want the data rendered as a collection of points, a collection of triangles or perhaps just one long line? Those hints are called primitives and are given to OpenGL while calling any of the drawing commands. Some of these hints are GL_POINTS, GL_TRIANGLES and GL_LINE_STRIP.

geometry shader

primitive assembly步骤的输出作为geometry shader的输入。geometry shader将一组形成primitive的vertex作为输入,geometry shader在此基础上通过生成新的点来生成新的primitive(可以和primitve assembly阶段生成的primitive不同)以此来生成其他新的形状。

rasterization

resterization步骤将geometry shader的输出作为输入,rasterization阶段将最终的primitive转换为最终显示在屏幕的像素点位置,并且将超出屏幕部分的去掉以提高性能。

fragment shader

fragment shader的主要目的是计算像素点的最终颜色,这个阶段一般是所有OpenGL高级特效生成的阶段。通常fragment shader包含可以用来计算最终像素颜色的数据,例如光照,光照颜色,阴影等信息。

A fragment in OpenGL is all the data required for OpenGL to render a single pixel.

alpha test and blender

在所有颜色值都已经被决定后,会进入到alpha test和blender阶段。这个阶段会检查frament的深度信息和stencil信息,判断这个fragment是在其他object的前面还是后面,一次判断是否需要最终渲染这个fragment。另外这一步也会检查alpha通道,以此来混合(blend)颜色信息。因此,即使在fragment shader中计算出了像素的输出颜色,最终像素的实际颜色也可能会和计算出来的不同。

可以看到,一个渲染管线包含了很多步骤和很多可配置的渲染属性。但是,在大多数情况下,我们只需要和处理vertex shader和fragment shader就可以了。geometry shader是可选的并且通常用默认的geometry shader实现就可以了。vertex shader和fragment shader是现代OpenGL要求用户至少提供的两个shader,这两个shader没有默认的实现。