关于GPU和渲染不知道的那些事

一、GPU简介

GPU(Graphics Processing Unit):一种可进行绘图运算工作的专用微处理器。GPU 能够生成 2D/3D 的图形图像和视频,从而能够支持基于窗口的操作系统、图形用户界面、视频游戏、可视化图像应用和视频播放。GPU 具有非常强的并行计算能力。GPU 的并行计算能力使其能够快速将图形结果计算出来并在屏幕的所有像素中进行显示。

GPU 及其相关驱动实现了图形处理中的 OpenGL 和 DirectX 模型,从而允许开发者能够轻易地操作硬件。OpenGL 严格来说并不是常规意义上的 API,而是一个第三方标准(由 khronos 组织制定并维护),其严格定义了每个函数该如何执行,以及它们的输出值。至于每个函数内部具体是如何实现的,则由 OpenGL 库的开发者自行决定。实际 OpenGL 库的开发者通常是显卡的生产商。DirectX 则是由 Microsoft 提供一套第三方标准。

关于GPU和渲染不知道的那些事


二、GPU渲染流程

GPU 图形渲染流程的主要工作可以被划分为两个部分:

  • 把 3D 坐标转换为 2D 坐标
  • 把 2D 坐标转变为实际的有颜色的像素

GPU 图形渲染流程的具体实现可分为六个阶段,如下图所示。

  • 顶点着色器(Vertex Shader)
  • 形状装配(Shape Assembly),又称 图元装配
  • 几何着色器(Geometry Shader)
  • 光栅化(Rasterization)
  • 片段着色器(Fragment Shader)
  • 测试与混合(Tests and Blending)

关于GPU和渲染不知道的那些事

第一阶段,顶点着色器。
标转为另一种 3D 坐标,同时顶点着色器可以对顶点属性进行一些基本处理。

第二阶段,形状(图元)装配。
该阶段将顶点着色器输出的所有顶点作为输入,并将所有的点装配成指定图元的形状。图中则是一个三角形。图元(Primitive) 用于表示如何渲染顶点数据,如:点、线、三角形。

第三阶段,几何着色器。
该阶段把图元形式的一系列顶点的集合作为输入,它可以通过产生新顶点构造出新的(或是其它的)图元来生成其他形状。例子中,它生成了另一个三角形。

第四阶段,光栅化。
该阶段会把图元映射为最终屏幕上相应的像素,生成片段。片段(Fragment) 是渲染一个像素所需要的所有数据。

第五阶段,片段着色器。
该阶段首先会对输入的片段进行 裁切(Clipping)。裁切会丢弃超出视图以外的所有像素,用来提升执行效率。

第六阶段,测试与混合。
该阶段会检测片段的对应的深度值(z坐标),判断这个像素位于其它物体的前面还是后面,决定是否应该丢弃。此外,该阶段还会检查 alpha 值( alpha 值定义了一个物体的透明度),从而对物体进行混合。因此,即使在片段着色器中计算出来了一个像素输出的颜色,在渲染多个三角形的时候最后的像素颜色也可能完全不同。

关于混合,GPU 采用如下公式进行计算,并得出最后的颜色。

R = S + D * (1 - Sa)

关于公式的含义,假设有两个像素 S(source) 和 D(destination),S 在 z 轴方向相对靠前(在上面),D 在 z 轴方向相对靠后(在下面),那么最终的颜色值就是 S(上面像素) 的颜色 + D(下面像素) 的颜色 * (1 - S(上面像素) 颜色的透明度)。

上述流水线以绘制一个三角形为进行介绍,可以为每个顶点添加颜色来增加图形的细节,从而创建图像。但是,如果让图形看上去更加真实,需要足够多的顶点和颜色,相应也会产生更大的开销。为了提高生产效率和执行效率,开发者经常会使用 纹理(Texture) 来表现细节。纹理是一个 2D 图片(甚至也有 1D 和 3D 的纹理)。纹理一般可以直接作为图形渲染流水线的第五阶段的输入。

关于GPU和渲染不知道的那些事


三、可编程着色器

上述阶段中的着色器事实上是一些程序,它们运行在 GPU 中成千上万的小处理器核中。这些着色器允许开发者进行配置,从而可以高效地控制图形渲染流水线中的特定部分。由于它们运行在 GPU 中,因此可以降低 CPU 的负荷。着色器可以使用多种语言编写,OpenGL 提供了 GLSL(OpenGL Shading Language) 着色器语言。

这里提到的这几个词语,都和渲染管线相关,渲染管线的英文pipeline,可能翻译成渲染流水线更好。您可以将其当成一个函数,函数内的实现又分为多个模块。

pipeline(param)

{

param_a = function_a(param);

param_b = function_b(param_a);

......

return param_x;

}

可以把以上这个函数画成流程图,实际上dx的手册里就是画流程图了。有输入,中间有很多模块按顺序处理最后输出,你可以把渲染管线的输出当成一个颜色的二维数组,返回给显示器。而其中的着色器 光栅化就是其中 function_xx内部使用到的实现细节,有时候我们使用这些名词来表示function_xx这个结构本身。

对于图形 api 的使用者来说,为了能正确显示图像,往往要对整个pipeline的过程,顺序有了解。

一简单流程如下:

管线程序段输入=>顶点着色器=>光栅化=>像素着色器=>屏幕颜色

(上一个函数的)输出 传递给=>(下一个函数作为)输入

下面简单举例过程帮助您理解:

使用opengl时,我们需要提供vertex buffer object index buffer object (vertex element array),也就是模型数据。您可以把这个模型数据当做pipeline的输入param。接下来就开始了管线内部流程。

输入的模型数据,会把顶点数组(vbo)中的每个点拆开,单独一个点当做参数输入到顶点着色器里,你可以把顶点着色器看成一个叫做vertex_shader()的函数,把整个过程想象成for_each(v in vbo){ vertex_shader(v); },或者一个多线程处理。处理完后,你的顶点会附着上一些通用信息,比如纹理uv之类的,

可以把一个顶点当做一个struct;管线会根据vbo ibo 拼成多个三角形,把这些三角形送入光栅化过程,三角形会被打散成一个个的小像素。这些像素会呗当做参数传入像素着色器,过程和顶点着色器类似。

对于可编程管线来说,vertexshader pixelshader(opengl里叫fragment shader 片段着色器)这两个函数,也需要在渲染前通过api设置好,你可以想象成在把你的函数安装到显卡上处理着色器的模块里去。

这个流程的模块,是会随着版本升级而有一些变化的。对于opengl来说,早期固定管线的内容,国内能接触到的教程,更多强调的是每个模块如何使用,怎么调用api,而忽略了管线模块的顺序这些说明,同时读者也会忽略管线模块输入输出这些令人困扰的内容。

关于GPU和渲染不知道的那些事


本文转自:荷阁科技,转载此文目的在于传递更多信息,版权归原作者所有。如不支持转载,请联系小编demi@eetrend.com删除。

最新文章