zifa2003293 发表于 2023-3-3 16:05

【unity卡通渲染】不拉直头发uv也能做的假各向异性高光

【前言】
本方法完全没有理论支撑,效果不严谨,仅适合不想改uv的懒人,而且就目前的测试来看只适用于【整体形状规则,大体接近球形】的头发模型,有的角度会有点怪(怎么限制这么多),各位轻喷ww。
如果不介意以上问题的话可以继续往下看了。
【正文】
一、先看效果:



blender里的效果



unity里面的效果



头发部分的UV,并不是直的

模型使用的是 模之屋:【深空之眼】诗蔻蒂
二、思路
这个效果其实是很偶然做出来的,当既不懂blender又不懂unity的我照着别人的代码在blender里面做出了这个效果时,我以为一切都是正常的。结果当我尝试在unity里面复现效果时,乱七八糟的高光给了我深深的疑惑==。
代码学习了这一篇Shader学习 (16)非物理各向异性Shader 作者:九猫
后来我细品了一下我在blender里面的做法,节点如下:


发现问题就出在黄字部分,它输入的“切向(正切)”和我们在unity中理解的并不一样。我们直接输出“切向(正切)”看一下:


看起来是世界空间的,而且也跟uv没有什么关系,但是居然能得到还算不错的结果,那我们就直接在unity里面抄一下吧。
1、首先,找个能做出上图效果的东西,我想到的是物体在模型空间的坐标,要注意:在blender中我把头发部分拆成了单独的物体(意味着头发的原点在头发的中心),但是unity中没有,所以头发的模型空间坐标的Y值会很大,Z值也有一点偏差,解决方法是直接把Y的值归零,Z值加上一个偏移值(自己调个差不多的就行)。
然后结果和blender可能还是有点不一样的:


2、我们知道unity的坐标系和blender不同,所以这里输出的蓝色(Z值)相当于blender中的绿色(Y值),除此之外,红色和蓝色分布的地方也不对,调整一下位置即可:
float3 FakeTangent= normalize(float3(i.modelpos.x,0,i.modelpos.z+_Zbias));
FakeTangent= float4(FakeTangent.z,FakeTangent.y,-FakeTangent.x,1);3、好了,接下来把这个假切线和法线叉乘一下得到假副切线,然后用常规的方法算高光就可以了。有可能遇到法线不够平整的问题会出现奇怪的结果(我在blender里面也是使用了平滑光照),可以把模型法线平滑一下看看


4、高光shader代码
Shader "test/hair"
{
    Properties
    {
      _Shift1("_Shift1",Range(-2,2)) = 0
      _Gloss1("_Gloss1",Range(0,600)) = 1
      _Zbias("_Zbias", Range(-0.1, 0.1)) = 0
      _LightDir("_LightDir",Vector) = (1,0,1,1)
    }
    SubShader
    {
      Pass
      {
            CULL OFF
            Tags {"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert2
            #pragma fragment frag
            #include "UnityCG.cginc"

            float _Shift1;
            float _Gloss1;
            float _Zbias;
            float4 _LightDir;

            struct appdata2
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
            };

            struct v2f2
            {
                float2 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
                float4 worldPos :TEXCOORD5;
                float3 normalDir : TEXCOORD2;
                float3 modelpos:TEXCOORD4;
            };

            v2f2 vert2 (appdata2 v)
            {
                v2f2 o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                float4 worldPos = mul(UNITY_MATRIX_M, v.vertex);
                o.worldPos.xyz = worldPos.xyz;
                o.worldPos.w = 1;
                o.normalDir = UnityObjectToWorldDir(v.normal);
                o.modelpos=v.vertex.xyz;
                return o;
            }

            fixed4 frag (v2f2 i) : SV_Target
            {
                float3 FakeTangent= normalize(float3(i.modelpos.x,0,i.modelpos.z+_Zbias));//用来算头发高光的
                FakeTangent= float4(FakeTangent.z,FakeTangent.y,-FakeTangent.x,1);
                float3 normalDir = normalize(i.normalDir);
                float3 FakeBionormal=cross( normalDir,FakeTangent);

                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                float3 viewDir = normalize(_WorldSpaceCameraPos - i.worldPos.xyz);

                float3 tangent1 = normalize(FakeBionormal + _Shift1 * normalDir);
                float3 H1 = (normalize(_LightDir) + 0.8*viewDir);//这里0.8随便写的,减少视线方向的影响使效果更稳定
                float dotTH1 = dot(tangent1, H1);
                float sinTH1 = sqrt(1.0 - dotTH1 * dotTH1);
                float dirAtten1 = smoothstep(-1, 0, dotTH1);
                float S1 =pow(sinTH1, _Gloss1);
                return S1;
            }
            ENDCG
      }

      // shadow casting support
      UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"
    }
    Fallback "Diffuse"
}我自己调整的参数:



Gloss1有点太离谱了,可以用其他方法优化一下

最后整合到自己的shader里面,感觉高光效果还可以

Doris232 发表于 2023-3-3 16:14

好棒的高光!真好看!

量子计算9 发表于 2023-3-3 16:20

谢谢[爱心]

Arzie100 发表于 2023-3-3 16:20

横向辫子会有问题。

Doris232 发表于 2023-3-3 16:21

对,只有头上那一圈的高光能看[大哭]

kirin77 发表于 2023-3-3 16:24

差不多就是把头发当成一个圆柱来算切线[思考]

XGundam05 发表于 2023-3-3 16:24

试试用flowmap

TheLudGamer 发表于 2023-3-3 16:29

谢谢,了解了一下感觉很有用[种草]
页: [1]
查看完整版本: 【unity卡通渲染】不拉直头发uv也能做的假各向异性高光