根据和美术沟通,了解到卡通人物的边缘光效果和我们通常做的边缘光效果会有点区别,卡通人物的边缘光要有比较强硬的过度效果。
如果用普通的边缘过度效果,会有两个问题:
1。会带一些过度色,不会那么强硬的截断
2。通常做的都时跟摄像机与人物的法线点乘做的,这样并不能做到跟光线相关的边缘光效果。
我修改了两处地方来还原这个效果。
1.根据夹角的数值来决定截断的位置
2.不要用摄像机与人物法线点乘,换为用光源与人物法线做点乘
VtoS vertex_shader(Input v)
{
。。。。。。
float3 worldN = normalize(mul((float3x3)unity_ObjectToWorld, v.normal));
data.Normal=worldN;
float3 lightDirNorm=normalize(_EBGCharDirectionToLight0.xyz*_LightDir.xyz);
data.lightDir=lightDirNorm;
float3 V = WorldSpaceViewDir(v.vertex);
V = mul(unity_WorldToObject, V);//视方向从世界到模型坐标系的转换
data.NdotV.x = saturate(dot(v.normal, normalize(V)));//必须在同一坐标系才能正确做点乘运算
。。。。。。
}
fixed4 fragment_shader(VtoS s) : COLOR0
{
。。。。。。
half lDotN = dot(normalize(-s.lightDir), s.Normal);
half rim = 1 - saturate(lDotN );
float3 rimlight = (lDotN < -0.1 ? 1 : 0) * pow((1 - s.NdotV.x), _RimPower)* _RimColor.rgb;
。。。。。。
c.rgb += rimlight;
c.a = mainTex.a;
}
其他代码请自行补充了
如有其他意见,欢迎评论
注意:
1.计算过程如果一方归一化后另一方也要归一化,不然计算会涉及一些不相关的部位。
data.NdotV.x = saturate(dot(normalize(v.normal), normalize(V)));
2.其实这里光照计算不需要用到真实光照,只需要知道一个光照方向就好了,模拟出真实光照感觉。因为如果用真实光,如果你每个场景人物的旋转角度不一致,那么看上去是不一致的,那么这时要调整光照。那么调整光照方向就是最直接的。
float3 lightDirNorm = normalize(_LightDir.xyz);
data.lightDir = lightDirNorm;
之后只需要用这个光照方向去计算边缘光,暗部渲染,高光等就好了,注意如果用到matcap,matcao的高亮部位要跟这个方向一致。
3.做matcap的时候我们会发现摄像机越远他会出现越多的不相关暗部。
这里是因为摄像机角度渲染时mask图涉及的区域可能会超过范围,这里渲染的就会超过一点影响到贴图的其他部位。那么要减少这个影响,就应该根据摄像机的远近来处理uv。减少影响。
(step(uvx1, s.uv_main.x) * step(s.uv_main.x, uvx2)) > 0 ? (_UseMatCap > 0 ? ((mask.a != 0) ? float3(c.rgb * matMaskACapColor * 1.5) : float3(c.rgb * matCapColor * _MatCapColor * 1.5)) : c.rgb) : c.rgb;
(step(uvx1, s.uv_main.x) * step(s.uv_main.x, uvx2))是说uv的x限制在uvx1和uvx2之间。
当超过了这个像素 就用回c.rgb。其他部分都是matcap部分,就不细说了。