上周我们公司原画师画了一张很好看的镭射衣服原画,这个材质号称原画师一画就废的材质。BulingBuling的。我们原画师非常强,画的真好。看到后很有实现的欲望。于是我要挑战一下设计界甲方的最高难度,五彩斑斓黑的哥哥,五彩斑斓白。说了这么多,其实非常非常容易,核心代码就几句话的事情。我是在拾人牙慧。并且实现的方式也不止一种。
先上最后效果图
1 分析
首先我们先了解一下,这种效果会在哪里用到,比如:车漆的反射,泡泡,这种比较洋气的镭射衣服也会用到。但是镭射衣服一般外面还会有一层类似透明雨披的东西或者就是透明的。我这里没有现成的模型就没有去制作,要是想做的话把模型丢进MAX挤出一层也可以。
这里我找了一些五彩斑斓白的参考:
这个图让我想起来小时候外婆家猪圈棚就是这个纸
话说我也挺想做这种的,奈何没有找到类似的模型,自己又懒得做(其实是做的丑),只能找个裙子凑合凑合(所以说啊,美术大佬就非常重要)
这种的把猪圈棚纸当雨披穿的,颜色相对上面的比较饱和,类似UE4的HueShift节点
但是本文不是基于这个UE节点的算法制作的,这里就不去赘述。
2 思考
看完上面的图,那么问题来了,我们常见的泡泡是不是也是这种?没错,泡泡也可以认为是具有偏振彩色反射的。但是泡泡有一个更加洋气的名字,叫薄膜干涉。
感兴趣的同学可以去这个github库看看。
去年春节的时候我也实现过一个类似的,跟我有一年塑料朋友圈友情的朋友应该见到过。
仔细观察这种材质,大概就是彩虹色渐变+反光+透明(如果有的话)光的原理涉及到光的干涉。题外话,大家知道一根筷子进水和空气会发生一次折射,那么泡泡是一个闭合的球体,会发生两次折射。当然我们这里实现的是不透明的衣服,折射不在我们的考虑范围内,我们考虑反射就好。
首先我们想一下,这个不灵不灵的效果,和什么有关呢?灯光方向?视口方向?摄像机的位置?法线方向?
3 实现
对,其实都有关系 ,首先我们来讲解一下灯光方向,即世界空间的灯光方向,一个float3的向量,但是我们这里假设灯光是不变的就只有一盏光,光照模型中我们也假设是一个标准的PBS光照模型(如果讲清PBS真的要讲几天几夜,这里我就直接用的Unity标准的表面着色器,对标ASE的stanrad,毕竟本文重点是偏振幅彩色反射),向量具有方向性视口方向同理,即显示生活中我们人眼的观察方向(需要归一化)。
这里的代码实现原理是用摄像机位置减去空间物体的位置得来的结果。
// 视觉方向v。即相机到物体的向量归一化。// 等价UnityWorldSpaceViewDir(mul(unity_ObjectToWorld,v.vertex))fixed viewDir = normalize(_WorldSpaceCameraPos.xyz - mul(unity_ObjectToWorld,v.vertex).xyz);
Unity为我们定义好了摄像机位置的参数,在UnityShaderVariables.cginc这个文件中我们可以查到
#define _WorldSpaceCameraPos unity_StereoWorldSpaceCameraPos[unity_StereoEyeIndex]
直接可以通过_WorldSpaceCameraPos 这个方法拿到对应的向量数据
节点版本:我们这里使用了摄像机位置和一个float值相乘,为什么?下面第二个Debug给大家看。再和世界空间法线点乘获得值
Debug(1):
我们发现当我旋转视口的时候(即当前的摄像机位置产生了变化),颜色变化了。
然后我们将点乘的值给Cos函数后,再给一个蓝色。
Debug :可以看到,当我移动摄像机位置和远近的时候,颜色会发生不同程度的偏移,当我缩放上面的Tile值时,蓝色部分重叠的也就更加频繁
我想这里大家应该是可以理解的,我再解释一下:
摄像机位置距离越远,点乘值就会改变,而点乘是可以与float值相乘且满足交换律的。当我的值发生了变化,Cos也就发生了变化,cos是一个波浪弧线,当里面的自变量越大,弧线也就越密集。就会得到上面的效果。
那么我们对应的表面着色器代码应该怎么写呢?
(这里照顾一下新人能够实现效果,说了一下创建)
首先我们先创建一个表面着色器
创建后发现里面有代码,没错,里面已经预制了一个完整的PBS,我们只需要填充就好(当然,这里得解释一下,对于没有了解过UnityShader
机制的朋友来说,表面着色器完全是一个黑合。如果没有研究过PBR的实现方式,并不知道Unity到底帮我们做了什么。很方便,但是Pass和变体也很多)不过对练习和初学来说却非常好入门。
以下为全部代码:
Shader"Custom/CustomFilm"{Properties{_Metallic("Metallic",Range( 0 , 1)) = 1_ContrastMask1("ContrastMask1",Color) = (0,0,1,1)_Smoothness("Smoothness",Range( 0 , 1)) = 1_Tile("Tile",Float) = 1_MainTex("MainTex",2D) = "white" {}_MainColor("MainColor",Color) = (1,1,1,0)_MaskRgb("MaskRgb",Color) = (1,1,1,0)}SubShader{Tags{ "RenderType"="Opaque" }CGPROGRAM #pragma surface surf Standard fullforwardshadows #pragma target 3.0sampler2D_MainTex;structInput{float2uv_MainTex;float3worldNormal;};half_Smoothness;half_Metallic;half_Tile;half4_MainColor;half4_MaskRgb;half4_ContrastMask1;voidsurf (Input IN, inout SurfaceOutputStandard o){half3WorldNormal = normalize (IN.worldNormal);half3CameraPos = _WorldSpaceCameraPos * _Tile;half3DotPostion = dot (CameraPos,WorldNormal);half3Mask01 = saturate ( cos (DotPostion) * _ContrastMask1.rgb);half3CrossColor = cross (_ContrastMask1.rgb , float4(1,1,1,1));half3Mask02 = saturate ( sin (DotPostion) * CrossColor);half3AddMask = Mask01 + Mask02;halfRGBToGray = saturate ( 0.2989 * AddMask.r + 0.587 * AddMask.g + 0.114 * AddMask.b);half4c = tex2D (_MainTex, IN.uv_MainTex) * _MaskRgb;half3FinalColor = lerp (c , _MainColor , RGBToGray);o.Albedo = FinalColor.rgb;o.Metallic = _Metallic;o.Smoothness = _Smoothness;o.Alpha = 1;}ENDCG}FallBack"Diffuse"}
这个还是很容易的,我们首先去定义Properties内我们用到的所有东西
同时定义好声明类型
OK,这个时候,我们往输入结构体内获得世界法线。
相对于Unlit来讲,表面Shader封装的非常完美,不需要我们再进行矩阵转换获得世界空间的法线
在输出结构体内归一化后进行下面的计算,计算步骤和上面节点过程是一样的。
好,回归节点:我们下面要计算sin
这里和上面一样,不重复废话了。
然后我们将蓝色(0,0,1)和白色(1,1,1)叉乘结果就是垂直于这两个三维向量的向量所代表的颜色(这里是叉乘的性质,不了解的需要学一下数学基础)注意哦,叉乘是不满足交换律的。我没有用normalize是想增强颜色对比。
最后我们与sin相乘着色与之前的蓝色相加,红绿蓝三个通道就出来了。
对应的代码
下面,我要这个相加后的三维向量,给我变成一个灰度图。因为我是用来做线性插值(Lerp)的变量的。
这里就涉及到一个RGB转灰度的公式了,有三种常用的转法,ASE自带转灰度的节点,Unity好像也是带的,但是我忘了是哪个函数,知道的朋友可以下面告诉我。
最常用也最类似的的转灰度公式即是这个(一个经验数据):RGB 按照 0.2989 R,0.5870 G 和 0.1140 B 的比例构成像素灰度值我们这里相加即可,因为并不重复,也可以使用三个通道的值相加后除3,求一个平均值。
我们拿到了一个float值后传给lerp
既然要做五彩斑斓的白,我们lerp的AB值肯定要有一个是白的,这张花花绿绿的图是什么?这张图不得不提一句,是经过图形界大量的工作科研者测量出来的一个偏振彩色图(当然你要使用PS自己拉一个渐变也可以的,达到效果即可,同理UE4的一个HueShift节点。图形第一奥义:看起来是对的就是对的。)
对应的代码:
这里扯一下Lerp这个函数,当我用自研引擎写glsl时,我才知道Unity封装的是有多好,GLSL内对应的Lerp函数叫mix,也就是说我每一种情况都要考虑到,不能和Unity内一样(相对来说Unity的写法比GLSL随意多了)。
最后,如果想加上一点亮晶晶的颗粒感,可以用视口方向点乘世界空间法线(给一张法线贴图,UV平铺给高)这里我就直接用图表表示了,以下是图表和效果
本文到这里就结束啦,感谢各位看官,如需要工程文件,可以加群:867472754里面找 ,一起讨论问题。欢迎各路神仙!
如果遇到上文问题或者错误可以联系我,敬请斧正!
举报/反馈

Thepoly

2924获赞 1899粉丝
专注最前沿的艺术设计分享
关注
0
0
收藏
分享