薄膜干涉尝试记录

实习需要用到薄膜干涉的效果,看到《王者荣耀》里,婉儿的皮肤,尝试用仅有的一点知识去模仿下(待继续优化)

分析

康康目前我能做什么

  1. 在旋转模型的时候颜色会根据光照和视线的变换发生变化,因此需要注意法线和视线 — 菲涅尔现象,法线和光线对效果产生的影响。
  2. 基础的光照模型 — 反射相关

贴图

贴图有两张,一张是通过在ps里ramp得到的

一张来自中国科普博览

尝试

在最简单的材质球上实现的时候,先看NdotV的变换,中间为1,边缘为0与NdotV相符

接着添加一个贴图并通过NdotV进行采样,这个时候什么角度看都是一样的

接着加入光的影响,可以看到有根据希望的方向进行变化,既会收到光的影响也会收到视线的影响(背光面会有分界)

想到之前做过matcap的一个效果,首先尝试通过菲涅尔直接对贴图采样观察效果

1
2
3
4
half NdotV = dot(normal_dir, view_dir * _Tile);
half fresnel = 1.0 - NdotV;
half2 uv_thinfilm = half2(fresnel, 0.5);
half4 matcap_color = tex2D(_ThinfilmTex, uv_thinfilm);

可以看到效果的变化很单一也并没有实现对应的要求,因此尝试根据薄膜干涉原理来达到效果,根据Thepoly大佬这篇文章,思路主要是通过NdotV对灰度的影响进行变化,但是大佬在纹理采样的时候仍然用的是正常的uv值,因此做出来的效果并不是我的目标,因为我希望纹理能够根据视线和光线产生变化。为此进行如下的修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// NdotV
half NdotV = dot(normal_dir, view_dir * _Tile);
// 蓝色
half3 Mask01 = saturate(acos(NdotV)*2/UNITY_PI * half3(0,0,1));
// 蓝色和白色叉乘得到绿色,这里是为了拿到绿色通道 --- 可以手动计算下看结果,有saturate所以-1会修正
// --- 绿色和白色叉乘得到红色
// --- 红色和白色叉乘得到蓝色
half3 CrossColor = cross (half3(0,0,1) , half3(1,1,1));
// 绿色和红色
half3 Mask02 = saturate (asin(NdotV)*2/UNITY_PI * CrossColor);
// 得到红,绿,蓝三色通道
half3 AddMask = Mask01 + Mask02;
// 转灰度
half Rgb2Gray = saturate(0.2989 * AddMask.r + 0.587 * AddMask.g + 0.114 * AddMask.b);
// 这里是修改的地方
half4 col = tex2D(_BubbleTex, half2(NdotV,NdotL));

把shader加到之前记录的实验模型里得到效果如下,感觉更近了一步

接着可以看到,颜色只是很单纯的白色,需要加入衣服本身的颜色信息,所以通过灰度对原本衣服的颜色和薄膜干涉的颜色进行了插值

1
half3 thin_film = lerp(col, base_color, Rgb2Gray);

目前的计算仍然是有些问题(但是感觉效果再调整一下可以用),灰度计算上通过cos直接对NdotV的值直接进行计算,按照天源大佬的文章,需要加入弧度对薄膜干涉进行映射,因此做了如下两处的修改

1
2
3
4
5
6
7
8
// 修改前
half3 Mask01 = saturate(cos(NdotV) * half3(0,0,1));
...
half3 Mask02 = saturate (sin(NdotV) * CrossColor);
// 修改后
half3 Mask01 = saturate(acos(NdotV)*2/UNITY_PI * half3(0,0,1));
...
half3 Mask02 = saturate (asin(NdotV)*2/UNITY_PI * CrossColor);

最后换一套白色的贴图可以看到,发现对比度有点高

通过替换直接的叠加方式,换成one minus

1
half3 soft_thin_film = thin_film + base_color * (1-thin_film);

在婉儿的衣服上能够看到比较光滑的质感,因此通过matcap添加玻璃材质进行模拟, 这里把ramp贴图左右对调了一下,可惜衣服其他材质不太像

1
2
3
half3 normal_viewspace = mul(UNITY_MATRIX_V, float4(normal_dir, 0.0)).xyz;
half2 uv_matcap = (normal_viewspace.xy + float2(1.0, 1.0)) * 0.5;
half4 matcap_color = tex2D(_MatcapBase, uv_matcap) * _MatIntensity;

参考

Thepoly

天源