糖尿病康复,内容丰富有趣,生活中的好帮手!
糖尿病康复 > Unity Shader 学习笔记(27)渲染轮廓线(描边)方法 卡通风格渲染 素描风格渲染

Unity Shader 学习笔记(27)渲染轮廓线(描边)方法 卡通风格渲染 素描风格渲染

时间:2023-03-19 17:11:49

相关推荐

Unity Shader 学习笔记(27)渲染轮廓线(描边)方法 卡通风格渲染 素描风格渲染

Unity Shader 学习笔记(27)渲染轮廓线(描边)方法、卡通风格渲染、素描风格渲染

参考书籍:《Unity Shader 入门精要》

渲染轮廓线(描边)

五种方法:

基于观察角度和表面法线。即视角方向和表面法线点乘结果判断(接近0,表示面接近垂直与视角)。过程式几何。两个Pass:第一个Pass渲染背面并且让轮廓可见(顶点外扩);第二个Pass正常渲染正面。适应于大多数表面平滑的模型,不适合立方体等平整模型。基于图像处理。前面两种边缘检测就是了:直接用算子判断和使用深度和法线纹理。但如果一些深度和法线变化很小的无法检测出来,如桌子上一张纸。基于轮廓边。检测方法:相邻两个三角是否一个面向视角,另一个背向视角,就是边。即 (n0·v > 0) ≠ (n1·v > 0)。 缺点是轮廓是逐帧单独提取的,帧与帧之间会出现跳跃性。混合上述方法。首先找到轮廓线(方法4),把模型和轮廓边渲染到纹理中,再使用图像处理识别轮廓线(方法3),在图像空间进行风格化渲染。

卡通风格渲染

使用描边方法2,以及卡通风格的高光反射光照模型实现。

描边注意:在背面顶点扩展时,可能有正面的面,这时会出错。可想象一个半实心球,内部有个面向视角的面,顶点外扩时,内部的面会超出外表面,遮挡了外表面。解决办法是先让背面法线z值减0.5再归一化(背面压扁)。

高光实现:镜面反射使用Blinn模型,计算(n·h)时,做阈值比较,小于的就是高光部分。

Shader "Custom/Chapter 14/Toon Shading" {Properties {_Color ("Color Tint", Color) = (1, 1, 1, 1)_MainTex ("Main Tex", 2D) = "white" {}_Ramp ("Ramp Texture", 2D) = "white" {}// 漫反射渐变纹理_Outline ("Outline", Range(0, 1)) = 0.1// 轮廓线宽度_OutlineColor ("Outline Color", Color) = (0, 0, 0, 1)// 轮廓线颜色_Specular ("Specular", Color) = (1, 1, 1, 1)_SpecularScale ("Specular Scale", Range(0, 0.1)) = 0.01// 高光反射的阈值}SubShader {Tags { "RenderType"="Opaque" "Queue"="Geometry"}// 第一个Pass,延展背面顶点,实现描边。Pass {NAME "OUTLINE"Cull Front// 剔除正面,只渲染正面...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,基于Blinn光照模型,使用自定义高光光照模型,实现高光。Pass {Tags { "LightMode"="ForwardBase" }Cull Back...float4 frag(v2f i) : SV_Target { ...fixed spec = dot(worldNormal, worldHalfDir);// 高光区域抗锯齿操作,fwidth:邻域像素的近似导数。fixed w = fwidth(spec) * 2.0;// _SpecularScale为0会完全消除高光反射,smoothstep:小于-w为0,大于w为1,否则在0到1之间插值。fixed3 specular = _Specular.rgb * lerp(0, 1, smoothstep(-w, w, spec + _SpecularScale - 1)) * step(0.0001, _SpecularScale); return fixed4(ambient + diffuse + specular, 1.0);}ENDCG}}FallBack "Diffuse"}

素描风格渲染

通过判断不同光照下漫反射值,使用不同的渲染纹理。纹理组成一个色调艺术映射(Tonal Art Map, TAM)。

// 素描风格Shader "Custom/Chapter 14/Hatching" {Properties {_Color ("Color Tint", Color) = (1, 1, 1, 1)_TileFactor ("Tile Factor", Float) = 1// 平铺系数_Outline ("Outline", Range(0, 1)) = 0.1_Hatch0 ("Hatch 0", 2D) = "white" {}// 6张素描纹理,模拟不同阴影使用的纹理_Hatch1 ("Hatch 1", 2D) = "white" {}_Hatch2 ("Hatch 2", 2D) = "white" {}_Hatch3 ("Hatch 3", 2D) = "white" {}_Hatch4 ("Hatch 4", 2D) = "white" {}_Hatch5 ("Hatch 5", 2D) = "white" {}}SubShader {Tags { "RenderType"="Opaque" "Queue"="Geometry"}UsePass "Custom/Chapter 14/Toon Shading/OUTLINE"// 使用前面的描边渲染PassPass {...struct v2f {float4 pos : SV_POSITION;float2 uv : TEXCOORD0;fixed3 hatchWeights0 : TEXCOORD1;// 6张纹理存在两个fixed3中fixed3 hatchWeights1 : TEXCOORD2;float3 worldPos : TEXCOORD3;SHADOW_COORDS(4)};v2f vert(a2v v) {...o.hatchWeights0 = fixed3(0, 0, 0);o.hatchWeights1 = fixed3(0, 0, 0);float hatchFactor = diff * 7.0;// 放大7倍,便于分成7块,混合权重。if (hatchFactor > 6.0) {// 纯白} else if (hatchFactor > 5.0) {o.hatchWeights0.x = hatchFactor - 5.0;} else if (hatchFactor > 4.0) {o.hatchWeights0.x = hatchFactor - 4.0;o.hatchWeights0.y = 1.0 - o.hatchWeights0.x;} else if (hatchFactor > 3.0) {o.hatchWeights0.y = hatchFactor - 3.0;o.hatchWeights0.z = 1.0 - o.hatchWeights0.y;} else if (hatchFactor > 2.0) {o.hatchWeights0.z = hatchFactor - 2.0;o.hatchWeights1.x = 1.0 - o.hatchWeights0.z;} else if (hatchFactor > 1.0) {o.hatchWeights1.x = hatchFactor - 1.0;o.hatchWeights1.y = 1.0 - o.hatchWeights1.x;} else {o.hatchWeights1.y = hatchFactor;o.hatchWeights1.z = 1.0 - o.hatchWeights1.y;}o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;TRANSFER_SHADOW(o);return o; }fixed4 frag(v2f i) : SV_Target {fixed4 hatchTex0 = tex2D(_Hatch0, i.uv) * i.hatchWeights0.x;fixed4 hatchTex1 = tex2D(_Hatch1, i.uv) * i.hatchWeights0.y;fixed4 hatchTex2 = tex2D(_Hatch2, i.uv) * i.hatchWeights0.z;fixed4 hatchTex3 = tex2D(_Hatch3, i.uv) * i.hatchWeights1.x;fixed4 hatchTex4 = tex2D(_Hatch4, i.uv) * i.hatchWeights1.y;fixed4 hatchTex5 = tex2D(_Hatch5, i.uv) * i.hatchWeights1.z;// 全白和最浅的纹理混合。fixed4 whiteColor = fixed4(1, 1, 1, 1) * (1 - i.hatchWeights0.x - i.hatchWeights0.y - i.hatchWeights0.z - i.hatchWeights1.x - i.hatchWeights1.y - i.hatchWeights1.z);fixed4 hatchColor = hatchTex0 + hatchTex1 + hatchTex2 + hatchTex3 + hatchTex4 + hatchTex5 + whiteColor;UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);return fixed4(hatchColor.rgb * _Color.rgb * atten, 1.0);}ENDCG}}FallBack "Diffuse"}

如果觉得《Unity Shader 学习笔记(27)渲染轮廓线(描边)方法 卡通风格渲染 素描风格渲染》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。