可编程渲染管线与着色器语言

转载自:http://www.cppblog.com/Leaf/archive/2013/02/22/198015.aspx

一、3D渲染管线工作流程

输入3D模型,输出2D图片

image

数据填充

当我们想实现一次渲染效果的时候,数据的提交(填充)是不可缺少的。因此,工作流程的第一步就是要处理输入的数据;

二我们最直接的接触3D渲染流程的时机,就是数据填充时,更确切的说,就是那一堆set数据的API。

数据填充允许我们提交我们想要的数据,比如顶点数据(如位置,法线,颜色,纹理坐标等)。常亮(世界矩阵,观察矩阵,投影矩阵,纹理因子等等)。

image

 

 

变换&顶点光照

在这个阶段,顶点会经过世界变换,观察变换,投影变化(本地坐标系->世界坐标系->摄像机坐标系->投影坐标系)。通常情况下,在顶点经过观察变换后,便开始做一些光照计算,这一阶段是可编程管线所提供的顶点处理阶段。也就是说,我们可以通过着色器程序来控制这一阶段的结果。在着色器程序中,我们可以任意地处理想要的数据,比如进行纹理坐标缩放,旋转,随机偏移等等。

image

面处理(前期):面的组装(全都由引擎自动完成)

面的组装:

在unity中采用Triangle Strip进行组装

裁剪&光栅化

当经过坐标变换和光照后,顶点已经被投影为2D坐标+深度信息。一些不可见的顶点会被裁剪调,比如背面的点。同时,剩下的顶点会被插值计算,以形成由像素构成的图元。所有的信息都会被插值,如纹理坐标,法线,颜色等。

image

面处理(后期):面的截取,面的剔除  (全都由引擎自动完成)

面截取 (摄像机视锥体外的截取掉)

摄像机看不见的不渲染

面剔除

1、反面剔除 

2、近截面远截面剔除 (相机近截面和远截面的对象的剔除)  通过硬件提供的深度缓存(Depth Buffer 或者 Z-buffer)来进行判断是否在摄像机有效的距离内。 这里的深度指面距离镜头所在平面的距离

3、遮挡剔除   去掉覆盖在其他面后面的面的部分,  也通过深度缓存的支持才可以计算

像素处理

像素处理阶段是最耗时,但也是最能够使你的渲染效果品质更高的地方,像素最终的样子会在此决定,你可以进行纹理映射,纹理混合,模糊,扩散等效果。

这也是可编程管线中可以用SHADER控制的另一个处理过程。

image

像素的一些额外处理和输出

当像素经过像素处理阶段后,并不能都有机会输出到屏幕上,因为还要经过深度(也有一些比较优化的渲染管线将深度测试提到了像素处理前)和模板测试,ALPHA测试,经过这些测试后,还要进行一次ALPHA混合,这次与目标缓冲区的混合,就能够实现半透明效果。虚拟世界中的五光十色就是因为这个半透明效果而生动。

image

---------------------------------------------------------------------------------------------------------------

在3D渲染流程中,我们能够用着色器语言控制的就是“顶点变化和光照”以及“像素处理”阶段。大概介绍一下GPU中用于处理着色器的最基本的帮手 - 寄存器

image

GPU中的寄存器与CPU的普通寄存器有一点不用,GPU中的每一个寄存器都是一个四维向量寄存器,即一个寄存器拥有4个浮点分量。通常用(x,y,z,w)或者(r,g,b,a)来表示。

输入寄存器

输入寄存器是GPU用来接收数据的寄存器,当我们将渲染数据填充到GPU时,其实就是讲这些数据填充到这些输入寄存器上。

比如,我们将一个顶点的位置和法线提交后,GPU在处理这个顶点时,其对应的寄存器就会拥有这个顶点相应的值。

顶点处理阶段和像素处理阶段用到的输入寄存器是不同的,输入寄存器决定了对应的处理阶段能够做的事情。

比如,我们提交了一个三角形的顶点和纹理坐标信息,并且我们提交了一张纹理,用来对这个三角形做纹理映射。但是,我们是不能在顶点处理阶段就对其他纹理。因为我们不能在顶点处理时访问纹理数据(如果真要这样,那就只能够使用顶点纹理了,这个内容超出了本次介绍的范围)。

常亮寄存器

常亮寄存器用来向着色器传递我们所需要控制的常量信息,比如,世界矩阵,观察矩阵,投影矩阵,纹理矩阵。以及我们可以设置一些值,比如当前时间,用来实现偏移一个定点的纹理坐标,使其纹理呈移动的效果。又或者通过这个值,动态改变定点的位置,使其出现波动效果,这些就是常量寄存器可以干的事情。

临时寄存器

临时寄存器使我们能够在着色器处理的过程中存放一些值,鶸你是用高级着色器语言编写着色程序,那你是感觉不到临时寄存器存在的,因为你仅仅是声明了一个临时变量,但确实,这就是临时寄存器的功劳。它才是真正的幕后黑手。

纹理采样寄存器

纹理寄存器用于存放你提交的纹理,并且提供纹理采样功能。如临近点采样,双线性采样,三线性采样等。这些都肯定你的知识来做相应的工作。它主要是辅助你完成纹理映射工作。

输出寄存器

输出寄存器就是你着色程序能够输出的呢绒,输出内容通过输出寄存器传递出来。顶点处理程序的输出有两种,一种是输出到帧缓冲,另一种是输出给像素处理程序,最典型的就是纹理坐标数据,当顶点处理程序拿到输入寄存器传递过来的纹理坐标值后,经过一些处理,又输出。二真正需要使用这个信息的,就是像素处理程序。

常有的有位置,纹理坐标,颜色等。

二、着色器语言

image

这里多了一个几何着色程序,这个是后来新加入的兄弟,传统的着色程序不能增加删除顶点。 但是,它可以。

着色器语言有高级语言和低级语言两种。 低级语言采用的是汇编那种助记符方式。

如 dp4 r0,v0,c0 这样的,表示将v0,c0点乘,并放入临时寄存器r0中。

而高级语言则是C风格的,很符合人们的编程习惯。 与传统的编程语言发展规律是相同的。

如 float temp = dot(dir,normal);

而常见的着色器语言中,低级语言如D3D中的LLSL,以及Adobe新出的Statge3D协同工作的AGAL.

高级语言如 CG,HLSL,GLSL应该很熟了吧。

CG是NVIDIA公司出的语言,它可以在D3D和OPENGL中工作,但需要使用NVIDIA对应的SDK。

HLSL是D3D协同工作的高级着色器语言。

GLSL是OPENGL协同工作的高级着色器语言。

posted @ 2015-12-03 11:16  我爱吃橙子  阅读(472)  评论(0编辑  收藏  举报