【UnityShader_Ojors的脚印】 在Shader之前_渲染那些事
发表于2016-11-09
在开始本文章之前,我想先推荐几本相对比较好的关于Shader的书,后续如果发现更好的书我会在后续的文章中推荐,毕竟文章很多内容都是我自己的理解,不能保证完全正确,大家可以根据自己的情况对书籍进行选读,我也是通过这些书籍和结合网上前辈们的博客进行学习的。大家共勉!
《GPU编程与CG语言之阳春白雪下里巴人》
《Cg教程_可编程实时图形权威指南》
《Unity Shader入门精要》
相信很多使用过别人写的Shader的同学都有这样的感受:下载下来的Shader,先用IDE打开看一下代码,对着看不懂的语法和一堆数学计算,嗯,一脸懵逼,算了不看了,直接用下试试,调下参数,运行,哇,这效果好赞,怎么做到的?!
那到底什么是Shader呢?
着色器(英语:shader)应用于计算机图形学领域,指一组供计算机图形资源在执行渲染任务时使用的指令,用于计算图像的颜色或明暗。但进来,它也能用于处理一些特殊效果,或者视频后处理。用layman的话来说,着色器告诉电脑如何用特有的一种方法去绘制物体。
程序员将着色器应用于图形处理器(GPU)的可编程流水线,来实现三维应用程序。这样的图形处理器有别于传统的固定流水线处理器,为GPU编程带来更高的灵活性和适应性。以前固有的流水线只能进行一些几何变换和像素灰度计算。现在可编程流水线还能处理所有像素、顶点、纹理的位置、色调、饱和度、明度、对比度并实时地绘制图像。着色器还能产生如模糊、高光、有体积光源、失焦、卡通渲染、色调分离、畸变、凹凸贴图、边缘检测、运动检测等效果
从技术的角度来看,着色器是渲染器的一个部分,它负责计算目标的颜色。
随着图形处理单元的进步,主要的图形软件库,像OpenGL和Direct3D都开始将目光投向更高阶的功能,即用着色器给新型的GPU编程,这就需要开发一系列的应用程序接口(API)满足着色功能。这样的改动出现在OpenGL的1.5版本和Direct3D的8版本。
以上是来自维基百科的解释,我的理解是:Shader是一种让程序员可以通过代码的方式参与图形渲染的一种技术,我们可以通过Shader让图形发生缩放、形变,并对像素点进行颜色的控制进而对图像进行美化。通过Shader,我们可以做出很多不可思议的效果。
那另一个问题由来了,什么是图形渲染?
要知道什么是图形渲染,首先要知道什么是渲染流水线。
流水线
学过计算机组成原理或者操作系统的同学可能清楚什么是流水线。
如果没有流水线会怎样呢?
见过工厂的生产流程吧?(没见过的百度一下。。。)比如一个零件需要分4步完成,每一步对应一个生产工人。没有流水线的话,生产一个零件,第一个工人需要等最后一个工人完成后才可以继续进行下一个零件的生产,这效率是极其低下的(要知道每个零件的生产时间内有3个工人在没事做玩手机啊),老板肯定不会这样安排生产的。
那有流水线呢?
在有流水线的情况下,每个工件的一步完成后马上转交第二个工人,第一个工人继续生产下一个零件。
流水线工人
流水线(图摘自《Unity Shader入门精要》)
由上图可见,有流水线后每个工人都在不停地工作,不停地转交零件,没有工人闲着没事做;而2图中可见效率的对比,使用流水线后可把生产效率提高好几倍,原来生产2个零件的时间,现在可以生产5个了!
那问题回来了,什么是渲染流水线呢?
在计算机图形渲染中,渲染流水线从游戏场景出发,生成一张显示在显示器上的二维图像。而这个过程,是由计算机的CPU和GPU通过流水线的形式共同参与的,极大地提高渲染效率。
渲染流水线3个概念阶段(图摘自《Unity Shader入门精要》)
在渲染流水线的三个阶段中,应用阶段由CPU参与,几何阶段和光栅化阶段由GPU参与,下面分别说一下:
应用阶段:
应用阶段(使用高级编程语言C#C++JAVA等)要渲染什么东西是由我们来决定的,CPU通过获取我们场景中的东西(模型、光源等)进行计算,该阶段结束,几何体的数据(顶点坐标、法向量、纹理坐标等)会传输到GPU中。
几何阶段:
几何阶段主要进行坐标变换,裁剪和投影等。简单来说就是对顶点进行变换,例如把在游戏场景中模型的顶点坐标映射到显示屏的坐标(显示屏拥有屏幕坐标系,每像素对应唯一坐标)上。该阶段结束,会把经转换后的坐标等信息传输到下一阶段。(当然不止有坐标信息,还有深度值、着色信息等)
光栅化阶段:
光栅化阶段其实就是根据上一个阶段的数据对显示屏上的像素点进行配色(着色),该阶段是针对屏幕的每个像素点进行操作的。
ps:几何阶段和光栅化阶段还分别对应着自己的GPU流水线。
GPU流水线
GPU流水线(图摘自《Unity Shader入门精要》)
过多的细节我不多说了,主要讲讲几何阶段的顶点着色器和光栅化阶段的片元着色器,这两个阶段是我们主要进行编程的阶段。
顶点着色器也就是VertexShader,在VertexShader中我们可以对模型顶点进行一些坐标转换或者形变,也可以通过计算和赋值把一些片元默认不含有的属性带入下一阶段(主要目标是FragmentShader)来进行一些需要的操作。
而片元着色器就是FragmentShader,光照处理和颜色的变换基本都是在这里进行的(当然在VertexShader中也可以进行光照计算,但是Fragment是针对屏幕像素进行处理,Vertex是针对顶点进行处理(当模型顶点数不多时,模型顶点的数量约束了光照的渲染效果),效果的好坏明显可见)
VertexShader光照效果(图摘自《GPU编程与CG语言之阳春白雪下里巴人》)
经FragmentShader处理后光照的效果(图摘自《GPU编程与CG语言之阳春白雪下里巴人》)
好了,关于渲染的这些底层的东西就先讲到这吧,讲太多也很难消化,当然我这里只是很浅层地讲了部分内容,要深入了解还是要多查阅,多思考。如果大家发现我有哪里理解错了或者有什么疏漏欢迎留言。