原神面部阴影的实现(大概)

本文探讨了如何在Unity中使用法线映射和投影算法解决面部光照问题,包括阈值图处理、左右采样、投影到平面的向量操作,以及针对面部模型的贴图调整。作者分享了解决法线方向不一致和光照变化过快问题的方法,以及最终修复后的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考: https://zhuanlan.zhihu.com/p/279334552?utm_source=qq
https://stackoverflow.com/questions/52339320/unity-shader-hlsl-equivalent-of-vector3-projectonplane

在这里插入图片描述

原理

在这里插入图片描述

  • 通过采样阈值图来完成,阈值图的制作方法不太清楚,参考里面应该可以做到。
  • 然后翻转贴图左右各采样一次,根据叉乘可以判断是左半边脸还是右半边。
Lambert = (Lambert * 0.5 + 0.5);
fixed LR = cross(worldForward, worldLightDir).y;
fixed4 col = tex2D(_MainTex, i.uv);
// 左右翻转
float2 flipUV = float2(1 - i.uv.x, i.uv.y);
fixed4 lightMap = fixed4(0,0,0,0);
fixed4 lightMapL = tex2D(_LightMap, i.uv);
fixed4 lightMapR = tex2D(_LightMap, flipUV);

lightMap = LR > 0 ? lightMapL : lightMapR
lightMap = lightMap.a > Lambert ? 1 - _ShadowColor.a : 1

col.rgb = lerp(_ShadowColor.rgb, col.rgb, lightMap.rgb);

直接利用法线

一开始我是直接用模型的法线来做角度采样,发现效果并不对。

float Lambert = dot(worldNormal, worldLightDir);

在这里插入图片描述
原因是因为每个点的法线朝向并不一致,导致采样错误

采用面部模型的朝向

于是我改了每个顶点的朝向

// vert
v2f vert (appdata v)
{
    v2f o;
    ............
    o.forward = normalize(UnityObjectToWorldNormal(float3(0,0,1)));

    return o;
}
// ps
........
float Lambert = dot(worldForward, worldLightDir);

在这里插入图片描述
会出现变化过于快的问题

光线方向改用投影

这里用到了向量投影到平面的算法

在这里插入图片描述

投影公式证明
在这里插入图片描述
记得要单位化一下

inline float3 projectOnPlane( float3 vec, float3 normal )
{
   return vec - normal * dot( vec, normal );
}
........
// frag
float Lambert = dot(worldForward, normalize(projectOnPlane(worldLightDir, float3(0,1,0))));

在这里插入图片描述
这样的话就没啥问题了。
可能有些错误,欢迎各位大佬指出哦,谢谢~~~~😁

三角区域反了

原来还有专业术语
在这里插入图片描述
在这里插入图片描述

我也反了。哈哈,改下代码就好,果然,美术还是要懂些的,不然你都不知道哪反了。敏感度啊,还好别人指出了

if(LR > 0)
{
       lightMap = lightMapR;
   }else
   {
       lightMap = lightMapL;
   }
   

   if(lightMap.a > Lambert)
   {
       lightMap = 1;
   }else
   {
       lightMap = 1 - _ShadowColor.a;
   }

上面代码还是有些问题

float2 flipUV = float2(1 - i.uv.x, i.uv.y);
fixed4 lightMap = fixed4(0,0,0,0);
fixed4 lightMapL = 1 - tex2D(_LightMap, i.uv);
fixed4 lightMapR = 1 - tex2D(_LightMap, flipUV);

if(LR > 0)
{
    lightMap = lightMapR;
}else
{
    lightMap = lightMapL;
}


if(lightMap.a > Lambert)
{
    lightMap = 1 - _ShadowColor.a;
}else
{
    lightMap = 1;
}

col.rgb = lerp(_ShadowColor.rgb, col.rgb, lightMap.rgb);

这会对了

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值