US5L11——表面着色器结构体
US5L11——表面着色器结构体
表面着色器结构体
表面着色器结构体主要分为两类:一是输入结构体、二是输出结构体
表面着色器函数的参数有三种固定格式:
-
void 表面函数名(Input IN, inout SurfaceOutput o)
-
void 表面函数名(Input IN, inout SurfaceOutputStandard o)
-
void 表面函数名(Input IN, inout SurfaceOutputStandardSpecular o)
其中 Input
结构体,就是输入结构体,而 SurfaceOutput
、SurfaceOutputStandard
、SurfaceOutputStandardSpecular
结构体,就是输出结构体
表面着色器输入结构体
表面着色器函数的参数列表中,Input
结构体,就是输入结构体,它是由我们自己声明的,是数据的来源,我们需要用到这些数据进行逻辑处理
输入结构体中我们能声明哪些成员
Input
结构体虽然是需要我们自己声明的结构体,但是我们只要在其中按照规定声明成员变量,便能获取到指定的表面属性
注意:
- 如果我们在可选额外参数中使用
vertex
自定义了顶点修改函数,该结构体还会是顶点修改函数的输出结构体- 除了规范好的参数,我们还可以自己添加自定义参数,比如在自定义顶点修改函数中进行赋值
- 在顶点 / 片元着色器中,这些参数往往需要我们手动计算,而在表面着色器中你可以理解为 Unity 内部已经帮助我们计算好了,直接拿来用即可
输入结构体的成员命名规定如下,只要按照规定声明成员,Unity 会内部自己计算并赋值给对应的成员:
1 | struct Input |
表面着色器输出结构体
表面着色器函数的参数列表中,SurfaceOutput
、SurfaceOutputStandard
、SurfaceOutputStandardSpecular
结构体,就是输出结构体
我们可以利用上文的输入结构体 Input
中的数据在表面函数中进行计算后,将计算结果赋值存储在输出结构体中,
之后 Unity 会利用我们输出的数据作为光照模型函数的输入来进行各种光照相关的计算,
这三个输出结构体是由 Unity 提前声明好的,不能自己增加和减少,如果我们没有对其中的某些变量赋值,会使用默认值
SurfaceOutput
SurfaceOutput
结构体(在 Unity 内置文件 Lighting.cginc 中声明),当我们在编译指令中使用 Lambert
和 BlinnPhong
光照模型时,就需要使用该结构体
SurfaceOutput
的定义如下:
1 | // Lighting.cginc |
其中,Specular
和 Gloss
镜面相关的两个参数,如果使用了 BlinnPhong
光照模型,会使用该公式计算高光反射强度:
1 | float spec = pow(nh, s.Specular * 128) * s.Gloss; |
其中 nh
是法线向量与半角向量点积值,即 max(0, dot(wNormal, halfA))
的值,具体计算方法详见:US3S1L6——Blinn-Phong式高光反射光照模型
SurfaceOutputStandard
SurfaceOutputStandard
结构体(在 Unity 内置文件 UnityPBSLighting.cginc
中声明),
当我们在编译指令中使用 Standard
光照模型时,就需要使用该结构体,我们一般称它为金属工作流输出结构体
1 | // UnityPBSLighting.cginc |
SurfaceOutputStandardSpecular
SurfaceOutputStandardSpecular
结构体(在 Unity 内置文件 UnityPBSLighting.cginc
中声明)
当我们在编译指令中使用 StandardSpecular
光照模型时,就需要使用该结构体,我们一般称它为高光工作流输出结构体
1 | // UnityPBSLighting.cginc |
表面着色器的渲染流程
目前我们已经了解了:编译指令、结构体、自定义函数(编译指令中的表面函数、光照模型、顶点函数、最终颜色修改函数)
我们只需要了解他们的具体作用便可以知道如何编写表面着色器,下图显式了表面着色器最终的渲染流程是如何把他们串联起来的
其中,黄色的步骤就是我们可以编辑修改的逻辑,灰色的是 Unity 自动生成的计算步骤