卡通风格渲染
基于色调的着色技术:使用漫反射系数对一张一维纹理采样,控制漫反射色调。
渲染轮廓线:
在这里使用几何轮廓线渲染,第一个pass渲染背面的面片,并让其轮廓可见,第二个pass渲染正常面片。这种方法适用于表面平滑的模型,不适合cube等平整模型。
用轮廓线颜色渲染整个背面,将顶点法线z分量固定,并将法线归一化后,将模型顶点沿着法线方向向外扩张一段距离 使轮廓可见。
添加高光:
卡通渲染中的高光反射除了计算半程向量与法线点乘结果外,需要进行小于某阈值的裁剪操作,使用CG提供的step函数实现此目的,直接如此会造成锯齿,可以在边界处小范围内进行平滑处理。smoothstep函数
未处理:
float spec= dot(worldNormal, worldHalfDir);
spec=step(阈值,spec);
抗锯齿处理:
spec=lerp(0,1,smoothstep(-w,w,spec-阈值));
和前面阴影实现的主要区别就是上面所说的内容,一个pass用于只渲染背面的三角面片,渲染状态要将正面关闭(Cull Front),完成用轮廓线颜色渲染整个背面。第二个pass用于完成正面。
第一个pass的vert
v2f vert (a2v v) {
v2f o;
float4 pos = mul(UNITY_MATRIX_MV, v.vertex);
float3 normal = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
normal.z = -0.5;
pos = pos + float4(normalize(normal), 0) * _Outline;
o.pos = mul(UNITY_MATRIX_P, pos);
return o;
}
第二个pass的frag:
float4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 worldHalfDir = normalize(worldLightDir + worldViewDir);
fixed4 c = tex2D (_MainTex, i.uv);
fixed3 albedo = c.rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
fixed diff = dot(worldNormal, worldLightDir);
diff = (diff * 0.5 + 0.5) * atten;
fixed3 diffuse = _LightColor0.rgb * albedo * tex2D(_Ramp, float2(diff, diff)).rgb;
fixed spec = dot(worldNormal, worldHalfDir);
fixed w = fwidth(spec) * 2.0;
fixed3 specular = _Specular.rgb * lerp(0, 1, smoothstep(-w, w, spec + _SpecularScale - 1)) * step(0.0001, _SpecularScale);
return fixed4(ambient + diffuse + specular, 1.0);
}
素描风格渲染
用提前生成的素描纹理来实现实时的素描风格渲染,暂不考虑论文中多级渐远纹理的生成,直接使用六张素描纹理进行渲染。关键在于混合权重。
个人感觉实现与六张简单叠加,相差效果不是特别大。