Chapter17 表面着色器
- 一、编译指令
- 二、两个结构体
-
- [1.Input 结构体:数据来源](#1.Input 结构体:数据来源)
- 2.SurfaceOutput
- 三、Unity背后做了什么
- 四、表面着色器的缺点
一、编译指令
- 作用:指明该表面着色器的 表面函数 和 光照函数,并设置一些可选参数
#pragma surface surfaceFunction lightMode [optionalparams]
:#pragma surface 用于指明该编译指令是用于定义表面着色器的,后面需要指明表面函数(surfaceFunction)和光照模型( lightMode),以及一些可选的参数
1.表面函数
surfaceFunction 用于定义对象的表面属性(反射率、光滑度、透明度等),通常是名为 surf 的函数(名字可以任意),格式是固定的
c
void surf(Input IN, inout SurfaceOutput o)
void surf(Input IN, inout SurfaceOutputStandard o)
void surf(Input IN, inout SurfaceOutputStandardSpecular o)
- 输入结构体 InputIN 来设置表面属性,并存储在结构体 SurfaceOutput、SurfaceOutputStandard、SurfaceOutputStandardSpecular 中(都是Unity内置结构体),再传递给光照函数计算光照结果
2.光照函数
使用表面函数中设置的各种表面属性,来应用某些光照模型。Unity内置了基于物理的光照模型函数 Standard 和 StandardSpecular( UnityPBSLighting.cginc),以及简单的非基于物理的光照模型函数 Lambert 和 Blinn-Phong(Lighting.cginc)
- 定义自己的光照函数
c
half4 Lighting<NAME> (SurfaceOutput s, half3 lightDir, half atten);
half4 Lighting<NAME> (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten);
3.其他可选参数
- 自定义的修改函数 :顶点修改函数(vertex:VertexFunction) 和 最后颜色修改函数(finalColor:ColorFunction)
- 顶点修改函数:自定义顶点属性(顶点颜色传递给表面函数、修改顶点位置、实现顶点动画等)
- 最后颜色修改函数:在颜色绘制到屏幕前,最后一次修改颜色值(实现自定义雾效等)
- 阴影 :
- addshadow:会为表面着色器生成一个阴影投射的Pass
- fullforwardshadow :可以在前向渲染中支持所有光源类型的阴影
- noshadow:禁用阴影
- 透明度测试和透明度混合 :alphatest 和 alpha
- 光照 :控制光照对物体的影响
- noambient:不应用任何环境光照或光照探针
- novertexlights不应用任何逐顶点光照
- noforwardadd:去掉前向渲染中的额外Pass,只支持一个逐像素的平行光,其他光源会逐顶点或SH方法来计算
- nolightmap、nofog等
- 控制代码生成:可以控制只使用前向或者延迟(Unity会为表面着色器生成前向渲染路径和延迟渲染路径用的Pass)exclude_path:deferred、exclude_path:forward和exclude_path:prepass
二、两个结构体
1.Input 结构体:数据来源
还支持自定义变量,采样坐标必须以uv为前缀,比如 uv_MainTex
2.SurfaceOutput
SurfaceOutput、SurfaceOutputStandard、SurfaceOutputStandardSpecular 会作为表面函数的输出,光照函数的输入来进行光照计算
- SurfaceSurfaceOutput
c
struct SurfaceOutput{
fixed3 Albedo;
fixed3 Normal;
fixed3 Emission;
half Specular;
fixed Gloss;
fixed Alpha;
};
- SurfaceOutputStandard、SurfaceOutputStandardSpecular:用于基于物理的光照模型
c
struct SurfaceOutputStandard{
fixed3 Albedo;
fixed3 Normal; //tangent space normal
half3 Emission;
half Metallic; //0=non-metal,1=metal
half Smoothness; //0=rough,1=smooth
half Occlusion;
fixed Alpha;
};
struct SurfaceOutputStandardSpecular{
fixed3 Albedo;
fixed3 Specular;
fixed3 Normal; //tangent space normal
half3 Emission;
half Smoothness; //0=rough,1=smooth
half Occlusion;
fixed Alpha;
};
三、Unity背后做了什么
Unity背后会为表面着色器生成真正的一个包含多个Pass(针对不同渲染路径的)的顶点/片元着色器。会为前向渲染路径 生成LightMode为ForwardBase和ForwardAdd的Pass;为延迟渲染路径 生成LightMode为Deferred的Pass;为了给光照映射和动态全局光照提取表面信息,Unity会生成LightMode为Meta的Pass
- Unity对ForwardBase的Pass的自动生成过程如下:
- 1.Unity会分析代码,据此生成顶点着色器的输出------v2f_surf结构体。Unity会分析我们在自定义函数中使用的变量,如果需要,就会在v2f_surf中生成相应的变量。有时在Input中定义了某些变量,但后面并没有使用时,v2f_surf不会生成
- 2.生成顶点着色器
- 3.生成片元着色器:使用v2f_surf来填充Input
四、表面着色器的缺点
- 在表面着色器上完成的,都可以在顶点/片元着色器中重现,但反之不成立
- 性能较差:失去了对各种优化和各种特效实现的控制
- 无法完成自定义的渲染效果:玻璃等