ShaderNote-素描風格的渲染

效果圖

在這裏插入圖片描述

素描

素描效果是非真實渲染章節實現的一個效果,還是蠻有意思的。

實現方法

主要是根據物體的光照係數,來決定哪些淺,哪些深,哪些白,然後再使用這些素描紋理,進行採樣填充。
輪廓線的實現,主要是頂點上的偏移,要注意的是它們是在視圖空間下 完成計算的,它只計算背面,因此需要 剔除前面。
主要實現

在頂點作色器中計算光照係數,根據光照結果來決定6張爲你的混合權重,並傳遞給片元作色器,然後在片元作色器根據這些權重來混合6張紋理的採樣結果。

定義所需的屬性

	Properties
	{
		_Color("Color",Color)=(1,1,1,1)
		_TintFactor("TintFactor",float)=8
		_OutLine("OutLine",Range(0,1))=1
		_OutLineColor("OutLineColor",Color)=(1,1,1,1)
		_Hatch0("Hatch 0",2D)="white" {}
		_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" {}
	}

計算輪廓線

pass
		{	
			Cull Front 
			Tags{"RenderType"="Opaque" "Queue"="Geometry"}
			  
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			float _OutLine;
			float4 _OutLineColor;
			struct a2v
			{
				float4 vertex:POSITION;
				float3 normal:normal;
			};
			struct v2f
			{
				float4 pos:SV_POSITION;
			};
			v2f vert(a2v v)
			{
				v2f o;
				float3 pos=UnityObjectToViewPos(v.vertex);
				float3 normal=mul((float3x3)UNITY_MATRIX_IT_MV,v.normal);
				normal.z=-0.5; //爲了防止內凹
				pos=pos+normalize(normal)*_OutLine;
				o.pos=mul(UNITY_MATRIX_P,float4(pos,1));
				return o;
			}
			float4 frag(v2f v):SV_TARGET
			{
				return fixed4(_OutLineColor.rgb,1);
			}
			
			ENDCG
		}

需要剔除前面,在片元着色器中,只計算描邊的顏色。
在頂點作色器中
o.pos=mul(UNITY_MATRIX_P,float4(pos,1)); 使用的是當前投影矩陣,把視圖空間下計算好偏移的pos轉換到當前投影空間下。

如果不設置法線 z可能會出現 這種情況
在這裏插入圖片描述
視圖空間下,法線*offset 就是向外擴展offet倍,歸一化後,只得到了垂直物體表面,向外的方向。

另一個通道 處理物體的前面,剔除背面

	pass
		{
			Cull Back
			Tags{"RenderType"="Opaque" "Queue"="Geometry"}

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_fwdbase
			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"
			struct a2v{
				float4 vertex:POSITION;
				float3 normal:NORMAL;
				float4 texcoord:TEXCOORD0;
			};	
			struct v2f
			{
				float4 pos:SV_POSITION;
				float2 uv:TEXCOORD0;
				float3 hatchWeight0:TEXCOORD1;
				float3 hatchWeight1:TEXCOORD2;
				float3 worldPos:TEXCOORD3;
				SHADOW_COORDS(4)
			};
			float4 _Color;
			sampler2D _Hatch0;
			sampler2D _Hatch1;
			sampler2D _Hatch2;
			sampler2D _Hatch3;
			sampler2D _Hatch4;
			sampler2D _Hatch5;
			float _OutLine;
			float _TintFactor;

			v2f vert(a2v v)
			{
				v2f o;
				o.pos=UnityObjectToClipPos(v.vertex);
				o.uv=v.texcoord.xy*_TintFactor;
				o.worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
				float3 worldNormal=normalize( UnityObjectToWorldNormal(v.normal));
				//float3 wordViewDir=normalize(UnityWorldSpaceViewDir(o.worldPos.xyz));
				float3 worldLightDir=-normalize(UnityWorldSpaceLightDir(o.worldPos));
				//float3 halfDir=normalize(wordViewDir+worldLightDir);

				o.hatchWeight0=float3(0,0,0);
				o.hatchWeight1=float3(0,0,0);
				float diff=dot(worldNormal,worldLightDir);
				diff=clamp(diff,0.005,1);//防止背部全黑

				float hatchFactor=diff*7;
				if(hatchFactor>6)
				{
					 
 				}
				else if(hatchFactor>5)
				{
					o.hatchWeight0.x=hatchFactor-5;
				}else if(hatchFactor>4)
				{
					o.hatchWeight0.x=hatchFactor-4;
					o.hatchWeight0.y=1-o.hatchWeight0.x;
				}
				else if(hatchFactor>3)
				{
					o.hatchWeight0.y=hatchFactor-3;
					o.hatchWeight0.z=1-o.hatchWeight0.y;
				}
				else if(hatchFactor>2)
				{
					o.hatchWeight0.z=hatchFactor-2;
					o.hatchWeight1.x=1-o.hatchWeight0.z;
				}
				else if(hatchFactor>1)
				{
					o.hatchWeight1.x=hatchFactor-1;
					o.hatchWeight1.y=1-o.hatchWeight1.x;

				}
				else
				{
					o.hatchWeight1.y=hatchFactor;
					o.hatchWeight1.z=1-o.hatchWeight1.y;
				}

				TRANSFER_SHADOW(o);
				return  o;
			} 

			fixed4 frag(v2f i):SV_TARGET
			{
				fixed4 hatchTex0=tex2D(_Hatch0,i.uv)*i.hatchWeight0.x;		
				fixed4 hatchTex1=tex2D(_Hatch1,i.uv)*i.hatchWeight0.y;		
				fixed4 hatchTex2=tex2D(_Hatch2,i.uv)*i.hatchWeight0.z;		
				fixed4 hatchTex3=tex2D(_Hatch3,i.uv)*i.hatchWeight1.x;		
				fixed4 hatchTex4=tex2D(_Hatch4,i.uv)*i.hatchWeight1.y;		
				fixed4 hatchTex5=tex2D(_Hatch5,i.uv)*i.hatchWeight1.z;		

				fixed4 whiteColor=fixed4(1,1,1,1)*(1-i.hatchWeight0.x-i.hatchWeight0.y-i.hatchWeight0.z-i.hatchWeight1.x-i.hatchWeight1.y-i.hatchWeight1.z);
				fixed4 hatchColor=hatchTex0+hatchTex1+hatchTex2+hatchTex3+hatchTex4+hatchTex4+whiteColor;

				UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);

				return fixed4(_Color.rgb*atten*hatchColor.rgb,1);
			}
							o.uv=v.texcoord.xy*_TintFactor;
							這裏是計算紋理的密集度

在vert中 計算diffuse= dot(n,l) n爲法線方向,l爲光照方向,
然後擴大7倍,分別對應6張紋理 和全白區域;
分別計算 x0 ,x0y0,y0z0,z0x1,x1y1,z1;的係數

在frag中

				fixed4 whiteColor=fixed4(1,1,1,1)*(1-i.hatchWeight0.x-i.hatchWeight0.y-i.hatchWeight0.z-i.hatchWeight1.x-i.hatchWeight1.y-i.hatchWeight1.z);

這裏白色 計算就是 全白色減去上面所有diffuse不爲0的情況,
用1 減去,是因爲 diffuse 最高爲1,代表全亮,這裏計算結束,所有剩下的就是亮的部分了。

				fixed4 hatchColor=hatchTex0+hatchTex1+hatchTex2+hatchTex3+hatchTex4+hatchTex4+whiteColor;

最後最終結果就是它們所有 採樣的顏色相加;
0,1,2,3,4,5,分別代表 模型的各個部分。
由淺到深。
最後再計算光照衰減, 就完成了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章