21.11.25 《Unity 2018 Shaders and Effects Cookbook》笔记Chapter4

4.Lighting Models

  1. 自定义光照模型(custom lighting model)

    1. 改变#pragma指令为:#pragma surface surf LightingModelName
    2. 创建一个名为Lighting + LightingModelName的函数
    3. 例:指令为【#pragma surface surf SimpleLambert】,创建对应函数【LightingSimpleLambert()】
  2. 当两向量点积为0时(求点积函数dot()),两向量成90°角(正交)

  3. 兰伯特反射

    1. 仅用点积作为光强的系数NdotL(N:Normal 表面法线 L:lightDir 光的方向)
    2. Unity已实现对应函数LightingLambert,可以直接使用#pragma surface surf Lambert(同时也有Phong、BlinnPhong)
    3. color.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten);
  4. ToonShader

    1. 仅用曲面函数得到卡通效果是代价极其昂贵且耗时的(extremely expensive and time consuming)

    2. 卡通阴影需要使用光照模型实现,被称为赛璐珞/赛璐璐(celluloid, 简写CEL)

    3. 使用坡道贴图决定收到的阴影,使用NdotL在坡道贴图上采样得到光强的系数

    4. 或者不使用坡道贴图,用NdotL的值在0到1之间等距采样 (snap),如:

      half cel = floor(NdotL * _CelShadingLevels / (_CelShadingLevels - 0.5);

  5. Unity还提供了观察方向viewDir,在自定义光照模型中是可选的,可以写

    1. half4 LightingCustomName (SurfaceOutput s, half3 lightDir, half atten)
    2. half4 LightingCustomName (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
  6. 冯氏反射(Phong, 镜面反射模型,带viewDir)

    1. 最终光强I = 漫反射颜色D + 镜面反射S

    2. D = NdotL(与兰伯特反射相同)

    3. S = (Reflection dot viewDir)p

      float spec = pow(max(0, dot(reflectionVector, viewDir)), _SpecPower);

    4. Reflection = 2 * N * (N * NdotL) - LightDir :向量代数中可以依此公式计算出来

      float3 reflectionVector = normalize(2.0 * s.Normal * NdotL - lightDir);

    5. c.rgb = (s.Albedo * _LightColor0.rgb * max(0,NdotL) * atten) + ( _SpecularColor.rgb *_LightColor0.rgb * spec);

  7. 布林冯模型(BlinnPhong模型)

    1. 使用半程向量(viewDir和LightDir)替代了反射向量R的计算,半程向量halfVector = |V + L|
    2. float3 halfVector = normalize(lightDir + viewDir);
    3. spec = pow(max(0, dot(s.Normal, halfVector)), _SpecPower) * _SpecularColor;
    4. color.rgb = (s.Albedo * _LightColor0.rgb * NdotL) + ( _SpecularColor.rgb *_LightColor0.rgb * spec) * atten;
  8. 各向异性镜面模型Anisotropic

    1. 创建数据连接,需要把anisoDir信息(存在tex中)传递给Lighting函数,在surf函数中可以计算出这个值(tex2D()函数),所以用到自定义的输出结构

      strutc SurfaceAnisoOutput { … } 设置surf(Input IN, inout SurfaceAnisoOutput o)

      设置fixed4 LightingAnisotropic(SurfaceAnisoOutput s, fixed3 lightDir, half3 viewDir, fixed atten)

    2. 计算半程向量halfVector和NdotL

    3. 计算HdotA,A是各向异性方向和法线的半程向量(可以反应反射方向和各向异性方向的夹角)

      fixed HdotA = dot(normalize(s.Normal + s.AnisoDirection), halfVector);

    4. 计算各向异性系数,用sin函数帮助修正上面得到的值,这个公式可以得到一个较暗的中间高光

      float aniso = max(0, sin(radians((HdotA + _AnisoOffset) * 180)));

    5. 用pow函数放大各项异性的影响,并乘以反射系数来降低总体强度

      float spec = saturate(pow(aniso, s.Gloss * 128) * s.Specular);

    6. c.rgb = ((s.Albedo * _LightColor0.rgb * NdotL) + ( _SpecularColor.rgb * _LightColor0.rgb * spec)) * atten;

  9. 注:注意到从书中摘抄的公式中,atten系数有些只乘在漫反射上,有些只乘在镜面反射上,有些两个都乘了,不清楚是作者故意为之还是其中有什么讲究,通过修改代码实验,肉眼也没有看出来区别;按照个人理解,光照衰减对两种反射都应该有影响,才疏学浅且眼光有限,故该问题留个人实力提升后解答

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值