【NPR】Unity3D非真實感渲染----鉛筆畫濾鏡
阿新 • • 發佈:2019-01-28
寫在前面
實現思維描述 鉛筆 素描,是一種以樸素的方式去描繪客觀事物,並且通常以單色的筆觸及點、線、面來塑造形體的方法。從字面而言,素描可以被理解為單色畫。廣義而言,它是一種運用線條來再現事物的藝術形式 感性地分析,個人認為素描等於明暗填充畫筆加上輪廓線,姑且先認為鉛筆畫等於明暗填充加上輪廓線組成 所需材料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 本人長期離線,歡迎任何提問