1. 程式人生 > >【NPR】Unity3D非真實感渲染----鉛筆畫濾鏡

【NPR】Unity3D非真實感渲染----鉛筆畫濾鏡

寫在前面

實現思維描述      鉛筆 素描,是一種以樸素的方式去描繪客觀事物,並且通常以單色的筆觸及點、線、面來塑造形體的方法。從字面而言,素描可以被理解為單色畫。廣義而言,它是一種運用線條來再現事物的藝術形式     感性地分析,個人認為素描等於明暗填充畫筆加上輪廓線,姑且先認為鉛筆畫等於明暗填充加上輪廓線組成      所需材料
Properties 
	{
	    //主圖片
		_MainTex ("Base (RGB)", 2D) = "white" {}
		//畫筆取樣0~5
		_PencilTex0("Pencil Texture0",2D) = "white" {}
		_PencilTex1("Pencil Texture1",2D) = "white" {}
		_PencilTex2("Pencil Texture2",2D) = "white" {}
		_PencilTex3("Pencil Texture3",2D) = "white" {}
		_PencilTex4("Pencil Texture4",2D) = "white" {}
		_PencilTex5("Pencil Texture5",2D) = "white" {}
		//素描的背景(即是紙張紋理)
		_PaperTex("Paper Texture",2D) = "white" {}
		//控制畫筆稠密的因數
		_TileFactor ("Tile Factor", Float) = 1
		//控制深度圖干擾的因數
		_TileFactor2 ("Tile Factor2", Float) = 1
	}


關於輪廓線      圖形學上關於輪廓線的演算法層出不窮,有sobel,canny等邊緣檢測演算法,然而我們這裡並不需要精確地知道輪廓線是否是真的輪廓線,我們只需要最終圖跑得出來就行了,所以我們使用一般的浮雕邊緣檢測就好(圖片向左上取一格後逐個相減,其實不一定是左上,取左下,右上,右下相減效果也不會差很多)
            fixed3 c = tex2D(_MainTex,i.uv);
                //Line,圖片向左上取一格
                fixed3 cOffset = tex2D(_MainTex, i.uv + i.MapOffset);
                fixed3 RGBDiff = abs(cOffset-c);
                fixed greys1 = Luminance(RGBDiff);
                greys1 = min(greys1,1);
                fixed4 FinalColor = fixed4((1-greys1).xxx,1);
     最終輪廓效果如下:
關於明暗圖 某個畫素的光暗強度約等於該畫素r乘以0.3,g乘以0.6,b乘以0.1(r,g,b分別為該畫素的紅綠藍通道的值),Unity提供函式Luminance來供我們使用 對於鉛筆畫來說,我們一般使用線條的稠密來表示光的強度,越稀疏越亮,越稠密越暗。
我們前面在這裡拿到鉛筆的筆畫六張下圖,我們根據圖片的亮度來選擇紋理填充圖畫       填充色塊的程式碼: 
           fixed3 c = tex2D(_MainTex,i.uv);
                fixed4 Paper =tex2D(_PaperTex,i.uv);
                fixed grey0 = Luminance(c);
                //InnerLum
                fixed LastPercent = 1.0;
                fixed Hatch0Percent = saturate(( grey0 - 0.8 ) / 0.2);
                LastPercent -= Hatch0Percent;
                fixed Hatch1Percent = (1-saturate(abs( grey0 - 0.8 )/ 0.2)) * max( LastPercent,0 );
                LastPercent -= Hatch1Percent;
                fixed Hatch2Percent = (1-saturate(abs( grey0 - 0.6 )/ 0.2)) * max( LastPercent,0 );
                LastPercent -= Hatch2Percent;
                fixed Hatch3Percent = (1-saturate(abs( grey0 - 0.4 )/ 0.2)) * max( LastPercent,0 );
                LastPercent -= Hatch3Percent;
                fixed Hatch4Percent = (1-saturate(abs( grey0 - 0.2 )/ 0.2)) * max( LastPercent,0 );
                LastPercent -= Hatch4Percent;
                fixed Hatch5Percent = (1-saturate(abs( grey0 - 0.0 )/ 0.2)) * max( LastPercent,0 );
                LastPercent -= Hatch5Percent;
                fixed4 hatchTex0 = tex2D(_PencilTex0, i.uv * _TileFactor) ;
<span style="white-space:pre">				</span>fixed4 hatchTex1 = tex2D(_PencilTex1, i.uv * _TileFactor) ;
<span style="white-space:pre">				</span>fixed4 hatchTex2 = tex2D(_PencilTex2, i.uv * _TileFactor) ;
<span style="white-space:pre">				</span>fixed4 hatchTex3 = tex2D(_PencilTex3, i.uv * _TileFactor) ;
<span style="white-space:pre">				</span>fixed4 hatchTex4 = tex2D(_PencilTex4, i.uv * _TileFactor) ;
<span style="white-space:pre">				</span>fixed4 hatchTex5 = tex2D(_PencilTex5, i.uv * _TileFactor) ;

將上面的兩幅圖片逐個畫素相乘可得出下圖的效果:

使用深度圖補充細節

    漫畫家繪製素描時線條不一定都是筆直的,線條的走向與物體表面的凹凸有關,彎曲會給人一種偽造的3D感覺。     關於深度圖的使用請看這裡,本來使用CameraDepthNormalsTexture來繪製表面更好,但我沒能成功獲取.........     原深度圖:         我們從現在開始給畫的亮度填充時加入深度圖的影響:
            fixed3 c = tex2D(_MainTex,i.uv);
                fixed grey0 = Luminance(c);
                //深度圖的影響
                float d = 1 - saturate(SAMPLE_DEPTH_TEXTURE (_CameraDepthTexture, i.uv + i.MapOffset));
                //InnerLum
                fixed LastPercent = 1.0;
                fixed Hatch0Percent = saturate(( grey0 - 0.8 ) / 0.2);
                LastPercent -= Hatch0Percent;
                fixed Hatch1Percent = (1-saturate(abs( grey0 - 0.8 )/ 0.2)) * max( LastPercent,0 );
                LastPercent -= Hatch1Percent;
                fixed Hatch2Percent = (1-saturate(abs( grey0 - 0.6 )/ 0.2)) * max( LastPercent,0 );
                LastPercent -= Hatch2Percent;
                fixed Hatch3Percent = (1-saturate(abs( grey0 - 0.4 )/ 0.2)) * max( LastPercent,0 );
                LastPercent -= Hatch3Percent;
                fixed Hatch4Percent = (1-saturate(abs( grey0 - 0.2 )/ 0.2)) * max( LastPercent,0 );
                LastPercent -= Hatch4Percent;
                fixed Hatch5Percent = (1-saturate(abs( grey0 - 0.0 )/ 0.2)) * max( LastPercent,0 );
                LastPercent -= Hatch5Percent;
                //取紋理時加入深度的干擾
                fixed2 UV = i.uv * _TileFactor + fixed2(0,d) * _TileFactor;
                fixed4 hatchTex0 = tex2D(_PencilTex0, UV) ;
				fixed4 hatchTex1 = tex2D(_PencilTex1, UV) ;
				fixed4 hatchTex2 = tex2D(_PencilTex2, UV) ;
				fixed4 hatchTex3 = tex2D(_PencilTex3, UV) ;
				fixed4 hatchTex4 = tex2D(_PencilTex4, UV) ;
				fixed4 hatchTex5 = tex2D(_PencilTex5, UV) ;

最終得到的效果如下,加入了深度的影響鉛筆的立體感更明顯些:
      關於濾鏡的使用請參考【Unity Shaders】使用Unity Render Textures實現畫面特效——建立畫面特效腳本系統      當然你也可以使用我的濾鏡指令碼來控制,不過本人的程式碼寫的好簡單也沒多少引數可調,並且需要專業版中的ImageEffect包------直接去調材質球就好
[ExecuteInEditMode]
public class UseMaterialDepth : MonoBehaviour 
{
	public Material curMaterial; 
	// Use this for initialization
	void Start () 
	{
		if (curMaterial == null || curMaterial.shader.isSupported == false) 
		{  
			enabled = false;  
		}
	}
	void OnRenderImage (RenderTexture source, RenderTexture destination)
	{
		ImageEffects.BlitWithMaterial(curMaterial, source, destination);
	}
	void OnEnable() 
	{
		camera.depthTextureMode |= DepthTextureMode.Depth;        
	}
	// Update is called once per frame
	void Update () 
	{
		if(curMaterial==null)
			enabled=false;
	}
}

本專案所有原始碼在Here 本人長期離線,歡迎任何提問