前面第一章我们知道了,UnityShader默认就使用pbr
以下,使用和分析的都是基于Surface Shader,表面着色器
这并不是什么一个特殊的着色器,或者是一个什么特效,只是一个“鸡肋”
UnityShader发展历史也和明显
- vf Shader
- sf Shader
- PBR x
第一章,我们用了一个搞不清楚是不是PBR的surface Shader,
所以我们再做了一下扩展,搞清楚到底不是PBR
具体手写Shader代码步骤如下
(其实漏了很多关键步骤,没兴趣的请直接跳去下面的光和Surf分项代码,比较全)
1.创建Shader,用Editor创建一个Surface Shader,名字随意
2.随便声明一下,有无lightmap并没有什么卵用,target3.0也不知道有什么卵用
//#pragma surface surf BlinnPhong //alpha:fade
#pragma surface surf BlinnPhong nodynlightmap
#pragma target 3.0
用到了BlinnPhong,则必须存在变量,就算不声明,也必须存在,内在的BlinnPhong(光线函数)估计会莫名奇妙的用上
(下面这么写是不行的,必须写上_SpecColor
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
//_SpecColor("Specular Color", Color) = (0.5, 0.5, 0.5, 0)
_Shininess("Smoothness", Range(0,1)) = 0.5
(.Normal也必须有)
//surf shader代码
float4 bumpColor = tex2D(_BumpMap, IN.uv_MainTex);
o.Normal = UnpackNormal(bumpColor).xyz;
3.必须改用SurfaceOutput,而不是Standard
void surf(Input IN, inout SurfaceOutput o){
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
o.Gloss = c.a;
o.Specular = _Shininess;
o.Alpha = c.a;
//没什么卵用
float4 bumpColor = tex2D(_BumpMap, IN.uv_MainTex);
o.Normal = UnpackNormal(bumpColor).xyz;
}
4.还可以支持vert, finalColor等方法,暂时没用上
自定义Lighting光照函数代码:
1.创建Shader
2.声明:
#pragma surface surf SelfMaskMap alpha noshadow
//surf 和 SelfMaskMap其实是连着声明,相当于 surf() , LightingSelfMaskMap()
3.定义方法
inline half4 LightingSelfMaskMap(inout SurfaceOutput s, half3 viewDir, UnityGI gi){
return half4(1, 1, 1, 1);
}
inline void LightingSelfMaskMap_GI(inout SurfaceOutput s, UnityGIInput data, inout UnityGI gi)
{
//s.GIData = data;
}
fixed4 LightingSelfMaskMap(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten){
return half4(1, 1, 1, 1);
}
这2个截然不同的方法,唯一不同就是有无UNITYGI
所以,我们知道并不是单单声明就可以了,还需要方法配合
作为新手,会觉得很困惑:
- 1个声明,2个写法
- 错误提示不明确,也没定位哪行
- 缺少文档
但是,作为程序老手,Shader能实现成这样,其实是相当”高级“的语法,虽然我之后会吐槽更多
写一个Lighting方法,如果参数含GI,会明确提示你缺一个_GI方法
也只有现代的node_js等框架会有这个提示,我并不是c++ c预言的链接,虽然看上去好像是
4.测试一下
(测试用了一个结构体 SurfaceOutput,至于各种结构体)
inline half4 LightingSelfMaskMap(inout SurfaceOutput s, half3 viewDir, UnityGI gi){
//return half4(0.1, 0.1, 0.1, 1);
return half4(s.Albedo,s.Alpha);
}
结构体可参考这:https://blog.csdn.net/avi9111/article/details/109730851
测试的结论,是lighting方法在surf方法后执行(虽然一般surf写最后,lighting都是插前面,一般的程序员都会这么干)
一般正常人的理解是surf相当于fragment。我们学图形学也是这么学的
正常的vf 顺序是
- vertex Shader
- commond buff,light等逻辑
- fragment Shader
而sfShader的顺序非要是
- vert
- surf
- Lighting
但其实官方声明的时候,都已经“暗示”了顺序(我盲测的,是不可能去看官方文档的,这辈子都不可能去看文档)
#pragma surface surf SelfMaskMap alpha noshadow
我还没说,这种情况呢,这种是经典的坑新手情况
#pragma surface surf SelfMaskMap vert:vert alpha noshadow
参考:
BlinnPhong函数