Unity Shader 学习笔记(27)渲染轮廓线(描边)方法、卡通风格渲染、素描风格渲染
来源:互联网 发布:linux版jdk1.8下载 编辑:程序博客网 时间:2024/04/28 10:23
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" // 使用前面的描边渲染Pass Pass { ... 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"}
阅读全文
0 0
- Unity Shader 学习笔记(27)渲染轮廓线(描边)方法、卡通风格渲染、素描风格渲染
- Unity Shader 学习笔记(11) 渲染队列、透明效果
- 【Unity】卡通风格的Shader(二)
- 【Unity Shader】新书封面 — Low Polygon风格的渲染
- Unity Shader学习笔记:渲染纹理
- Shader 学习笔记(一) 渲染流水线
- 【Unity Shader实战】卡通风格的Shader(一)
- 【Unity Shader实战】卡通风格的Shader(二)
- 【Unity Shader实战】卡通风格的Shader(二)(2)
- 【Unity Shader实战】卡通风格的Shader(二)
- 通过卡通渲染描边shader来学习Unity的Shader写法
- 通过卡通渲染描边shader来学习Unity的Shader写法
- 卡通渲染进展(一)
- 【卡通渲染】关于CG中的2D风格化
- Unity Shader入门精要笔记(一):渲染流水线
- Unity Shader 学习笔记(30) Unity中渲染优化技术
- unity shader学习笔记(十三)——Unity中的复杂光照之渲染路径
- 图像渲染(Shader)
- C语言的第一步
- 欢迎使用CSDN-markdown编辑器
- 杭电2017新生赛1008-友好整数
- POJ
- Java并发学习(五)-LockSupport里面的park和unpark
- Unity Shader 学习笔记(27)渲染轮廓线(描边)方法、卡通风格渲染、素描风格渲染
- centos7下创建快捷方式
- JS 基础详解
- JVM类加载的总结
- maven实现springboot-mybatis框架(2)
- 深入分析java web javac编译原理(其一)
- <context:component-scan base-package="com.a" /> 与<context:annotation-config />
- 使用spring-boot-starter-actuator http://localhost:8080/info无法获取到相应信息
- Java并发学习(六)-深入分析CAS操作