顶点着色器和片断着色器

顶点和片段着色器   

 必备知识

 熟悉Stage3D API。最好之前使用过VertexBuffer。在继续这个教程之前一定要先阅读本系列的第一个教程(Stage3D原理)

   所需软件

Flash Builder 4.5 Premium (Download trial)

Flash Professional CS5.5 (Download trial)

在本章中,你将对着色器(Shaders)有一个大概的了解。着色器是Stage3D渲染管道的核心。你将学到顶点和片段着色器是个什么东东,它们在3D渲染管道中扮演什么角色以及为什么它们是如此重要。

 

初识着色器

在本系列教程的上一篇文章:《Stage3D原理》中,你已经了解到Stage3D是如何基于可编程图形管道工作的。

Stage3D中的可编程图形管道是非常有用的,因为你可以通过编程来改变渲染行为。这对于以前的固定功能图形管道来说是一个巨大的进步,固定功能图形管道只负责把数据交给GPU,GPU接管所有渲染工作,开发者无法控制渲染过程。

然而,这也意味着,为了使用Stage3D,你必须自己编写一些额外代码来控制可编程管道。

我们在可编程图形管道中编写的小程序被称为着色器(Shaders)。着色器分为两种:顶点着色器和片段着色器(也叫像素着色器)。使用Stage3D渲染任何图形,你都需要至少编写两个着色器:一个顶点的,一个片段的,不然你的图形管线法工作。

着色器是在图形硬件GPU上运行的小程序,这与在CPU上运行的普通ActionScript代码不同。这是着色器程序和普通程序之间最重要的区别。

着色器只是在GPU中执行的程序。

在 Stage3D中,着色器被一个叫做Program3D的特殊的Stage3D API封装(Wrapped)了起来。Program3D提供创建着色器实例的功能,并负责将其传入GPU,接下来,着色器代码会被执行,Stage3D API允许ActionScript代码和着色器程序间的数据流通。

着色器运行起来是非常快的,这并不是在说ActionScipt慢。但是当你运行ActionScript时,因为它是在一个虚拟机里运行的,所以比起原生语言比如C++来说要慢些。所以现在需要3A级游戏都还在用C++编写。

有史以来第一次,你可以编写一个对于GPU来说原生的程序,所以它们运行起来跟原生的速度一样快。

 

理解着色器在可编程图形管道中如何工作

可编程图形管道决定Stage3D内容如何渲染(见图1)

图1 可编程图形管道单元示意图

回顾一下上面的图表,注意顶点和片段着色器是如何在管道中起决定性作用的。

当 你要渲染一个几何图形时,你会用一个VertexBuffer来定义构成几何图形的三角形,VertextBuffer中又包含一系列的顶点数据。来自 VertextBuffer中的顶点数据作为输入传递给着色器,在着色器中可以处理这些数据。GPU将顶点着色器的输出数据组装为三角形,然后这些三角形 被适当的剪裁以适应用户视域(viewport),接下来在光栅化单元被处理成一种新的格式:由片段(Fragments)组成的数据格式,片段是一种简 单的数据格式,每一个片段包含一个三角形在屏幕上能显示的所有像素。

片段中的数据内容通常由顶点着色器决定。事实上,顶点着色器可以将顶点属性参数作为自己的输出。光栅化负责将着色器输出的顶点数据在三角形上进行颜色插值(interpolate),使片段上的每个像素都得到正确的属性值。

例 如,有一个Vertex Buffer指定了顶点的颜色作为顶点属性,其中三角形的两个顶点被分别被指定为黑色和白色。顶点着色器会将这些顶点颜色数据作为输出,传递给管道中的下 一个处理单元。然后,片段的相对中间部位的某处,会被置为灰色,也就是黑色顶点和白色顶点的中间色。片段中接近白色顶点的像素颜色会亮一些,相反,接近黑 色顶点的像素会暗一些。

接下来,这些插值后未经处理的片段被传输给片段着色器,它利用这些数据来完成最终像素颜色的建立。

除了片段着色器接收的片段数据外,你还可以用ActionScript将一些纹理数据传递给片段着色器,供片段着色器取样。

 

顶点着色器原理

顶点着色器是在GPU上运行的小程序。顾名思义,顶点着色器是用来处理顶点数据的。一个顶点着色器就是一个处理顶点的小程序(老外说话真的很啰嗦!)

一 般来说,可以将几何图形顶点数据放在VertexBuffer中,然后将其上传至GPU。然后,可以用一种着色器语言:例如AGAL来编写一个顶点着色 器。顶点着色器程序将处理VertextBuffer中的每一个顶点,这就好像在着色器周围使用了一个for循环,但实际上你根本看不到这个for循环, 如下:

  1. for (var i:int = 0; i <vertexBuffer.length; i++)
  2. {
  3. executeVertexShader(vertexBuffer);
  4. }

复制代码

 

所以,VertexBuffer中的所有顶点都会被处理。

你还可以将常量以常量寄存器的形式传递给顶点着色器,每次运行着色器(每次调用Context3D::drawTriangles方法,渲染一个网格)时,都可以传入一个不同的值,着色器可以根据常量的值来调节它的算法和输出。

顶 点着色器的输入是一个或多个顶点属性(Vertex Attribute)组成的VertexBuffer。VertexBuffer中的顶点应至少指出了顶点的位置属性,这些位置属性通常指的是每个3D模 型(每个模型都有其自身的原点)本身的坐标。顶点着色器将这些位置信息转换为屏幕位置,以便可以正确的显示。VertexBuffer中可能还包括一些其 它顶点属性,例如,顶点颜色或纹理UV坐标等。顶点着色器将这些作为输出(最终经过处理的),以便其可在光栅化单元进行插值,然后作为输入传递给片段着色 器。

顶点着色器常常用来对场景中几何图形坐标进行矩阵变换。顶点的坐标作为一个矩阵输入到顶点着色器中,它会将VertexBuffer中的所有顶点进行矩阵变换。由于使用了硬件加速,这个过程非常高效,大大快于自己用ActionScript编写的代码。

让 人感兴趣的时,顶点着色器是完全可编程的,你可以以任何你想要的方式修改几何图形。例如,一个典型的骨骼顶点修改的程序:你定义了一组骨骼也就是骨架和其 上的皮肤(网格)。当骨骼旋转时,由于骨骼和皮肤连在一起,所以皮肤的形状会跟着变化。那我们如何来实现呢?最好的办法是将骨骼旋转(变换)数据传递给一 个顶点着色器,让它来适当的修改皮肤的动画和变形。

还有一些会用到顶点着色器的应用场景:模拟柔软纺织品或者可变形对象的表面。用顶点着色器来让一个网格根据参数的变化从一个形状变为另一个形状。

 

片段着色器原理

 

就像顶点着色器一样,片段着色器也是运行在GPU上的小程序。顾名思义,用它来处理片段。它们负责输出每个三角形像素的最终颜色。

基本上来说,它是这样运行的:片段着色器将顶点着色器输出的片段作为输入,片段的顶点属性已被光栅化单元进行了插值处理。

片段着色器执行的流程基本上也很像一个循环,如果你能把未经处理的片段想象成某种数据流,就叫片段流吧,片段着色器的处理就像代码中描述的一样:

  1. for (var i:int = 0; i <fragmentStream.length; i++)
  2. {
  3. executeFragmentShader(fragmentStream);
  4. }

复制代码

 

片段流之所以称之为未处理过的,是因为片段着色器还没有处理它,并计算出在屏幕上显示的像素的颜色。

片段着色器是可编程管道中的最最核心的部分。其普遍的作用就是计算各种各样的三角形像素颜色,从为着色顶点图形(vertex-colored geometries)计算的顶点属性颜色,和为纹理图形为计算的纹理及相关的UV纹理坐标。

但 是顶点着色器的功能远非制造这些简单的效果。实际上,现代3D游戏中令人惊叹的3D特效都是用片段着色器来生成的。例如,动态光源效果通常都是由片段着色 器完成。思考一下就会明白,动态光源意味着根据场景中已有的光源计算像素颜色,这与几何图形的位置、材料都有很大的关系,所以片段着色器是制作动态光源效 果的不二之选。

像水体环境映射之类的反射特效也都是由片段着色器完成的。片段着色器能生成世界上几乎所有的光影特效,以上提及的只不过是它的冰山一角。

最后要提一下的是,片段着色器决定了你在屏幕上能看到什么,所以,片段着色器才是影响渲染的核心代码。

 

下一步该看哪些内容

 

在本教程中,你已经学到顶点着色器和片段着色器是如何工作的。这两个着色器是Stage3DAPI渲染管道中的核心。着色器可以生成各种各样的3D视觉特效。着色器相关的在线技术文章有很多。本系列的下一个教程将学习AGAL着色器语言。

想要深入着色器的更多细节,我推荐nVidia出版的“GPU Gems”,此书已经免费。其内容并不针对Flash和Stage3D,但是会有助于了解着色器生成特效的相关知识。

GPU Gems: Part I -Natural Effects

GPU Gems2: Part I – Geometric Complexity

GPU Gems 3

 

作者:Marco Scabia

原文链接:http://www.adobe.com/devnet/flashplayer/articles/vertex-fragment-shaders.html

posted @ 2017-06-08 19:51  AaronBlogs  阅读(12805)  评论(0编辑  收藏  举报