设计目的
:顶点-几何-片元着色器处理方式比较适合gpu去理解,但是对人理解而言就显得比较晦涩。所以unity提供了一种适合人类理解的处理方式,也就是表面着色器-光照模型-光照着色器。它是在顶点-几何-片元着色器上面进行的一层抽象封装,最终还是会被unity翻译成顶点-几何-片元着色器的处理方式。
表面着色器:通常用来定义渲染相关的变量。
光照模型:就是选择兰伯特或者phong等光照模型。
光照着色器:就是用来处理光照衰减和阴影等。
两个结构体
:就是用来对表面着色器-光照模型-光照着色器进行数据传递的结构体。具体用法如下:
1.INPUT结构体:主要用来记录表面函数所需要的一些输入参数,是可以自定义扩展的。常见的参数如下:
2.SurfaceOutput/SurfaceOutputStandard/SurfaceOutputStandardSpecular结构体:用来保存表面函数输入参数,并作为输出参数提供给光照函数进行光照处理。其中相关结构体固定不可以扩展。而且选择兰伯特或者phong等普通的光照模型时,我们应该使用SurfaceOutput结构体来对应普通的光照函数。选择基于物理的Standard光照模型时,我们应该使用SurfaceOutputStandard结构体来对应金属流程的光照函数。使用基于物理的StandardSpecular光照模型时,我们应该使用SurfaceOutputStandardSpecular结构体来对应高光的光照函数。
编译指令
:是我们与unity进行交互的一种方式。对应的格式为:
#pragma surface 表面函数 lightMode [可选参数]
1.表面函数:格式为
void surf(INPUT IN, inout SurfaceOutput/SurfaceOutputStandard/SurfaceOutputStandardSpecular o)
,其中INPUT用来设置各种表面属性,交由SurfaceOutput/SurfaceOutputStandard/SurfaceOutputStandardSpecular 输出给光照函数进行光照处理。其中SurfaceOutput/SurfaceOutputStandard/SurfaceOutputStandardSpecular 根据选择的光照模型进行确定到底使用哪一个。
2.光照函数:格式为
hlaf4 Lighting光照函数名(SurfaceOutput/SurfaceOutputStandard/SurfaceOutputStandardSpecular s, half3 lightDir, half3 viewDir(可选),half atten)
。使用表面着色器函数中输出的表面属性,应用指定的光照模型来模拟物体表面的光照效果。
3.可选参数:对表面着色器的行为进行扩展,常见的可选参数如下:
自定义修改函数
:可以设置顶点修改函数,来修改某些顶点。也可以设置颜色修改函数,来修改某些颜色。
控制代码生成
:使用execude_path来控制表面着色器只能在某些渲染路径中自动生成的代码。
透明度测试和混合
:使用alpha进行透明度混合,alphatest进行透明度测试。
表面着色器在unity背后执行原理
:因为表面-光照模型-光照着色器处理方式是在顶点-几何-片元着色器上层的抽象封装,所以最终unity都会将其解析成多个pass,每个pass的执行过程大致如下所示:
1.生成顶点着色器处理函数并将顶点数据传递给该处理函数。在处理函数内部先用顶点修改函数,对顶点数据进行处理,然后填充v2f_surf结构体输出。
2.生成片元着色器来接收v2f_surf结构体数据,并填充到Input结构体中,然后将该结构体传递给表面函数进行处理,得到SurfaceOutput/SurfaceOutputStandard/SurfaceOutputStandardSpecular结构体,并将其传递给光照函数使用指定的光照模型来进行光照计算,将得到的片元颜色输入给最后的片元修改函数进行最后的处理,得到最终的像素颜色。
3.对应的处理流程图大致如下所示:
4.查看生成的顶点-几何-片元着色器代码,可以通过以下操作查看。
表面着色器的优缺点
:
1.优点:表面着色器是在顶点-几何-片元着色器上层的抽象封装,所以我们不用写复杂的代码,直接定义好相关的参数和编译指令就可以实现我们需要的效果。
2.缺点:表面着色器必须按照它的规则去写代码,自由度不高,而且内部生成的顶点-几何-片元着色器也不是最优的,往往会产生性能上面的问题。