• 卡通风格

特点:物体都被黑色的线条描边,以及分明的明暗变化等。

–卡通渲染方法

技术

方法

基于色调的着色技术

使用漫反射系数对一张一维纹理进行采样,以控制漫反射的色调

光照模型 – 高光效果

一块块分界明显的纯色区域

物体边缘部分绘制轮廓

基于模型的描边方法

适用屏幕后处理技术对屏幕图像进行描边

  • 绘制模型轮廓线《Real Time Rendering, third edition》

类型

方法

优点

局限

基于观察角度和表面法线的轮廓线渲染

轮廓线的信息 = 视角方向 · 表面法线

简单快速,可以在一个Pass中就得到渲染结果

描边效果不够好

过程式几何轮廓线渲染

使用2个pass。

1.渲染背面的面片,并使用某些技术让它的轮廓可见

2.正常渲染正面的面片。

快速有效,并且适用于绝大多数表面平滑的模型

不适应类似于立方体这样平整的模糊

基于图像处理的

利用边缘检测算子对图像进行卷积操作

适用任何类型的模型

一些深度和法线变化很小的轮廓无法被检测出来

基于轮廓边检测的轮廓线渲染

检测相邻的三角面片是否一个朝正面、一个朝背面

(n0 · v>0) 不等于(n1 · v>0)

可以检测出精准的轮廓线

复杂、帧与帧之间会出现跳跃性

混合上述的几种渲染

1.找到精确的轮廓边

2.把模型和轮廓边渲染到纹理中

3.使用图像处理的方法识别出轮廓线

4在图像空间下进行风格化渲染

  • 高光

高光反射模型

缺陷

优化

卡通

float spec = dot(normal, halfDir);

spec = step(threshold,spec);

点乘后与一个阈值做比较

会在高光区域的边界造成锯齿1

高光区域的边缘不是平滑渐变的,而是从0突变到1

可以在边界处很小的区域内,进行平滑处理

spec = lerp(0,1,smoothstep(-w,w,spec - threshold))

正常

float spec = pow(max(0, dot(normal, halfdir)), _Gloss)

/******************************************************
 * 过程式轮廓线渲染方法对模型进行轮廓描边
 Pass1:1.使用轮廓线颜色渲染整个背面的面片,
 2.对顶点法线的z分量进行处理,使它们等于一个定值
 3.把法线归一化后视角空间下把模型顶点沿着法线向外扩张,让背部轮廓线可见
 Pass2:光照模型,渲染模型的正面
 * ToonShader.Shader
 *****************************************************/
 Shader"ToonShader"{
 	Properties{
 		_Color("Color Tint", Color)=(1,1,1,1)
		_MainTex("Main Tex", 2D) = "white"{}
		_Ramp("Ramp Texture", 2D) = "white"{}		//控制漫反射色调的渐变纹理
		_OutLine("Out Line", Range(0,1)) = 1.0		//控制轮廓线宽度
		_OutLineColor("Out Line Color", Color)=(1,1,1,1)//轮廓线颜色
		_Specular("Specular", Color) = (1,1,1,1)	//高光反射颜色
		_SpecularScale("Specular Scale", Range(0,1))=0.01 //高光反射阈值
	}
	SubShader{
		Pass{
			NAME "OUTLINE"
			Cull Front	//只渲染背面
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			struc av2{
				float4 vertex : POSITION;
				float3 normal:NORMAL;
			};
			half _OutLine;
			float4 _OutLineColor;
			struct v2f{
				float4 pos:SV_POSITION;
			};
			v2f vert(av2 v){
				v2f o;
				float4 pos = mul(UNITY_MATRIX_MV, v.vertex);
				float3 normal = UnityObjectToViewPos(v.normal);
				normal.z = -0.5;
				pos += float4(normalize(normal), 0) * _OutLine;
				o.pos = mul(UNITY_MATRIX_P, pos);
				return o;
			}
			//描边
			fixed4 frag(v2f i):SV_Target{
				return float4(_OutLineColor.rgb, 1);
			}
			ENDCG
		}
		Pass{
			Tags{"LightMode" = "ForwardBase"}
			Cull Back //只渲染前面
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_fwdbase
			#include "UnityCG.cginc"
			#include"Lighting.cginc"
			#include "AutoLight.cginc"
			struct v2f{
				float4 pos : SV_POSITION;
				float2 uv: TEXCOORD0;
				float3 worldPos:TEXCOORD1;
				float3 worldNormal:TEXCOORD2;
				SHADOW_COORDS(3)	//阴影
			};
			sampler2D _MainTex;
			float4 _MainTex_ST;
			float4 _Color;
			sampler2D _Ramp;
			float4 _Specular;
			half _SpecularScale;
			v2f vert(appdata_img v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(Unity_ObjectToWorld, v.vertex).xyz;
				TRANSFER_SHADOW(o);
				return o;
			}
			fixed4 frag(v2f i):SV_Target{
				fixed3 wNormal = normalize(i.worldNormal);
				fixed3 wLightDir = normalize(UnityWordlSpaceLightDir(i.worldPos));
				fixed3 wViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
				fixed3 halfDir = normalize(wLightDir+wViewDir);
				
				fixed4 c = tex2D(_MainTex, i.uv);
				fixed3 albedo = _Color.rgb * c.rgb;
				//环境光
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);//光照衰减
				fixed diff = dot(wNormal, wLightDir);
				diff = (diff * 0.5 + 0.5) * atten ;
				fixed3 diffC tex2D(_Ramp, float2(diff, diff)).rgb;
				//漫反射
				fixed3 diffuse = _LightColor0.rgb * albedo * diffC ;
				
				fixed spec = dot(wNormal, halfDir);
				//光照边界做抗锯齿处理
				fixed w = fwidth(spec) * 2.0;
				//高光反射
				fixed3 specular = _Specular.rgb * lerp(0,1,smoothstep(-w,w,spec+_SpecularScale - 1)) * step(0.001, _SpecularScale);
				fixed3 col = ambient + diffuse + specular
				return fixed4(col, 0);
			}
 			ENDCG
		}
	}
	Fallback "Diffuse"
 }

unity减面插件 simply_d3

/// <summary>
/// 与阈值的比较
/// </summary>
/// <param name="a">参考值</param>
/// <param name="b">待比较的数值</param>
/// <return > a <= b ? 1 : 0 </return>>
 int step(a, b)
 
 /// <summary>
 /// 生成0到1的平滑过渡
 /// </summary>
 /// <param name="a">最小值</param>
 /// <param name="b">最大值</param>
 /// <param name="x">输入值</param>
 /// <returns>x<a ==>0; x>b ==> 1; a<x<b ==>[0,1]</returns>
float smoothstep(float a, float b, float x)
{
    float t = saturate((x-a)/(b-a));
    return t*t*(3.0 - (2.0*t));
}

/// <summary>
/// 邻域像素之间的近似导数值
/// </summary>
/// <param name="a">比较值</param>
/// <returns>x和y方向偏导数的绝对值的和,ddx、ddy函数获得</returns>
float fwidth(float a)
  • 素描风格
  • 多级渐远纹理

保持笔触之间的间隔,以便更真实地模拟素描效果

/******************************************************
 * 素描风格的渲染
 * 使用6张素描纹理进行渲染
 * 1.vertex:计算逐顶点的光照 ==>决定6张纹理的混合权重
 * 2.fragment:根据权重混合6张纹理的采样结果
 * HatchingShader.Shader
 *****************************************************/
 Shader ""{
 	Properties{
		_Color("Color Tint", Color)=(1,1,1,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"{}
		_OutLine("Out Line",Range(0,2)) = 0.1
		_OutLineColor("OutLine Color", Color)=(0,0,0,0)
		_TileFactor("Tile Factor", Float) = 1	//纹理的平铺系数,数值越大,模型上的素描线条越密
	}
	SubShader{
		Tags{"RenderType" = "Opaque" "Queue"="Geometry"}
		UsePass "OUTLINE"	//上一个shader的名字+pass 描边
		Pass{
			Tags{"LightMode" = "ForwardBase"}
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_fwdbase
			
  		 	d#include "Lighting.cginc"
	   		#include "AutoLight.cginc"
   			#include "UnityCG.cginc"
  				
			struct v2f{
				float4 pos :SV_POSITION;
				float2 uv:TEXCOORD0;
				fixed3 hatchWeights0:TEXCOORD1;
				fixed3 hatchWeights1:TEXCOORD2;
				float3 worldPos:TEXCOORD3;
				SHADOW_COORDS(4)
			};
			float _TileFactor;
			sampler2D _Hatch0;
			sampler2D _Hatch1;
			sampler2D _Hatch2;
			sampler2D _Hatch3;
			sampler2D _Hatch4;
			sampler2D _Hatch5;
			fixed _OutLine;
			float4 _OutLineColor;
			float4 _Color;
			
			v2f vert(appdata_base v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.texcoord.xy * _TileFactor;
				float3 worldLightDir = normalize(WorldSpaceLightDir(v.vertex));
				fixed3 worldNormal = normalize(UnityObjectToWorldNormal(v.normal));
				//获取漫反射系数【0,1】
				fixed diff = max(0, dot(worldNormal, worldLightDir)); 		
				o.hatchWeights0 = fixed3(0,0,0);
				o.hatchWeights1 = fixed3(0,0,0);
				//缩放到[0,7]
				float hatchFactor = diff * 7.0; 
				//纹理混合权重
				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 - o.hatchWeights0.x;
				} else if (hatchFactor > 3.0) {
					o.hatchWeights0.y = hatchFactor - 3.0;
					o.hatchWeights0.z = 1 - o.hatchWeights0.y;
				} else if (hatchFactor > 2.0) {
					o.hatchWeights0.z = hatchFactor - 2.0;
     					o.hatchWeights1.x = 1 - o.hatchWeights0.z;
				} else if (hatchFactor > 1.0) {
					o.hatchWeights1.x = hatchFactor - 1.0;
	          			o.hatchWeights1.y = 1 - o.hatchWeights1.x;
				} else {
					o.hatchWeights1.y = hatchFactor;
              				o.hatchWeights1.z = 1 - o.hatchWeights1.y;
				}
				TRASFER_SHADOW(o);
				return o;
			}
			fixed4 fragment(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 + hatchTex2 + hatchTex3 + hatchTex4 + hatchTex5 + hatchTex1 + whiteColor;
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
				fixed3 col = hatchColor.rgb * _Color.rgb * atten;
				return fixed4(col, 1.0);
			}
			ENDCG
		}
	}
	Fallback "Diffuse"
 }

unity减面插件 simply_d3_02