UnityShader学习之旅 --渲染

  • 卡通风格

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

–卡通渲染方法

技术方法
基于色调的着色技术使用漫反射系数对一张一维纹理进行采样,以控制漫反射的色调
光照模型 – 高光效果一块块分界明显的纯色区域
物体边缘部分绘制轮廓基于模型的描边方法适用屏幕后处理技术对屏幕图像进行描边
  • 绘制模型轮廓线《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"
 }

在这里插入图片描述

/// <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"
 }

在这里插入图片描述

免费卡通资源包
Photoshop素描纹理


  1. 抗锯齿 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值