自言自语
最近学习和工作中写的几个shader虽然都完成了,但过程着实让我感到难受和尴尬。因为前学后忘,导致很多压根儿没想到的小错误犯了。这种小错误排查起来还贼费劲。今天就做简单汇总。以备后续查阅警醒自己。
1、忘记pragma相应的灯光文件算法
一次在写一个PBR框架的shader中,发现自己怎么都无法得到一个正确的NdotL的表现 一行行return Debug之后 才发现是自己因为自己手撸shader没找模板起步 所以漏掉了一个关键的 pragma语句 导致得到的灯光向量错误。
//正常shader结构中 如果使用的是 前向渲染,那么必须要指明其lightmode 几句关键的话语不能忘记.要在相应的pass中写上如下语句 注意是Pass中
Tags{"LightMode" = "forwardBase"}
//之后也别忘记要得到正确的lightDir还要写上编译语句
#pragma multi_compile_fwdbase
//如果是多光源
#pragma multi_compile_fwdadd
//尽管URP下已经可以一个pass内进行多光源计算了 但builltin下还是得这么写
如上问题,全部写好后 才能使用
float3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
这样的语句 否则得到的光源方向是不正确的。当然 不写上面的语句也可以得到光源方向 那就是直接算吧
平行光就是
//向量节省点开销只用half3就行 注意大小写区别
half3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
//点光源或者spot光源
half3 lightDir = normalize(_WorldSpaceLightPos0.xyz - worldPos.xyz);
当然使用这两句话 还是得有一个条件 要引入Unity ShaderLab里的一个头文件
#include “UnityCG.cginc”
2、传参的时候的错误
之前在写shader的过程中,使用Unity内置的函数时,没有太注意传入参数的类型。侥幸的是竟然也一直没有遇到什么问题。然后随着写的越来越多。早前埋下的不注意传参类型的后果就越来越多。
比如昨天晚上写一个视差效果,就怎么都无法得到正确的视角方向。也是一顿return Debug 找到问题是出在了视角方向 viewDir上。当就不知道为什么。 后来今天请教有经验的大佬。找到了问题所在是自己再获得worldPos时,使用UnityObjectToWorldPos()内置函数传入的参数类型不正确。要传入的是float4的类型的顶点参数 结果我传入的是 v.vertex.xyz.导致顶点的w分量丢失。这样转换的时候就会出现齐次坐标空间的问题 以及顶点的深度问题吧
正确的写法如下 顺便一并写出常用内置函数的传参类型
· Builltin
以下是常用内置函数的传参类型 builltin管线常用函数如下
```csharp
float3 mul(unity_OjbectToWorld,float4 v); //这个要求传float4类型 就一定得是float4类型。。
float3 UnityWorldSpaceLightDir(float4 v); //这个要求传float4类型 但是写个float3类型也是可以的。。
float3 UnityWorldSpaceViewDir(float4 v);
float3 ObjSpaceLightDir(float4 v); //注意这里是Obj 而不是Object shit
float3 ObjSpaceViewDir(float4 v);
float3 UntiyObjectToWorldNormal(float3 normal);
float3 UnityObjectToWorldDir(float3 Dir);
float3 UnityWorldToObjectDir(float3 Dir);
float4 mul(unity_WorldToLight, float4(i.worldpos, 1)); //把世界空间下的顶点转换到光源空间下返回的xyzw四个分量
UNITY_LIGHT_ATTENUATION(atten,i,float3(worldPos)) //这句宏 最后一个参数是个三维的参数. 有时候忘记会直接传个四位的参数进来.这里要注意
· URP Universal Render Pipeline
URP下的顶点数据都是float3类型中进行计算 w分量被单独用作他用 不参与计算了 相应变量的数学习惯也有所改变 以 OS ObjectSpace 和 WS WorldSpace 来区分仅仅为习惯 不是强制 不过再引用一些内置函数的时候还是尊重这个习惯比较好
float3 GetVertexPositionInputs(float3 positionOS);
//举例使用方法
VertexPositionInputs input = GetVertexPositionInputs(v.vertex.xyz);
o.pos = input.positionCS;
float3 posWS = input.positionWS;
float3 GetVertexNormalInputs(float3 normalOS);
VertexNormalInputs normalinput = GetVertexNormalInputs(v.normal);
o.normal = normalinput.normalOS;
float3 normalWS = normalinput.normalWS;
嗯暂且就先记录这么多 日后有犯错的地方 再继续更新
总结
凡事还是不能马虎大意,操之过急.仔细谨慎,严格规范.才能从总的学习时间线上提升效率.不然因为这些疏漏的小错误 耽误很多时间. 自勉