先介绍一下表面着色器:
表面着色器实际上就是在顶点片元着色器上添加了一层抽象,顶点片元着色器是硬件能理解的渲染方式,而开发者应该使用一种更容易理解的方式。很多时候使用表面着色器,我们只需要告诉shader:“使用这些纹理去填充颜色。使用这个法线纹理去填充表面法线,使用兰伯特光照模型。其他的就不要来烦我了!”我们不需要考虑是使用前向渲染还是延迟渲染路径,场景中有多少点光源,他们的类型是什么,怎么处理这些光源,每个pass需要处理多少个光源灯问题。我们可以轻松实现常见的光照模型,甚至不需要和任何光照变量打交道,unity就帮我们处理好了每个光源的光照结果。一个表面着色器最重要的部分是两个结构体以及它的编译指令。其中两个结构体是表面着色器中不同函数之间信息传递的桥梁,而编译指令是我们和unity沟通的重要手段。
一、编译指令
编译指令是我们和unity沟通的重要方式,通过它可以告诉unity:“用这个表面函数设置表面属性,用这个光照函数模拟光照,我不要阴影和环境光,不要雾效!”只需要一句代码就可以完成这么多事情。
编译指令最重要的作用是指明该表面着色器使用的表面函数和光照函数。并设置一些可选参数,表面着色器的CG块中第一句代码往往就是他的编译指令。格式如下:
#pragma surface surfaceFunction lightModel [optionalparams]
其中#pragma surface 用于指明该编译指令是用于定义表面着色器的,在他后面需要指明使用的表面函数(surfaceFunction)和光照模型[lightModel]。同时,还可以使用一些可选参数来控制表面着色器的一些行为。
1.1 表面函数
表面着色器的优点在于抽象出了"表面"这一概念。与之前遇到的顶点/片元抽象层不同,一个对象的表面属性定义了它的反射率、光滑度、透明度等值。而编译指令中的surfaceFunction就用于定义这些表面属性。surfaceFunction通常就是名为surf的函数(函数名可以是任意的),它的函数格式的固定的:
void surf (Input IN,inout SurfaceOutput o)
void surf (Input IN,inout SurfaceOutputStandard o)
void surf (Input IN,inout SurfaceOutputStandardSpecular o)
其中后两个是unity 5中由于引入了基于物理的渲染而新添加的两种结构体。SurfaceOutput、SurfaceOutputStandard、SurfaceOutputStandardSpecular都是Unity内置的结构体,他们需要配合不同的光