天天看点

【NPR】Unity3D非真实感渲染----铅笔画滤镜 写在前面 使用深度图补充细节

写在前面

     本篇文章所使用图片素材大多来源于【NPR】非真实感渲染实验室

实现思维描述      铅笔 素描,是一种以朴素的方式去描绘客观事物,并且通常以单色的笔触及点、线、面来塑造形体的方法。从字面而言,素描可以被理解为单色画。广义而言,它是一种运用线条来再现事物的艺术形式      感性地分析,个人认为素描等于明暗填充画笔加上轮廓线,姑且先认为铅笔画等于明暗填充加上轮廓线组成     

【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);
           

     最终轮廓效果如下:

【NPR】Unity3D非真实感渲染----铅笔画滤镜 写在前面 使用深度图补充细节

  关于明暗图 某个像素的光暗强度约等于该像素r乘以0.3,g乘以0.6,b乘以0.1(r,g,b分别为该像素的红绿蓝通道的值),Unity提供函数Luminance来供我们使用 对于铅笔画来说,我们一般使用线条的稠密来表示光的强度,越稀疏越亮,越稠密越暗。

【NPR】Unity3D非真实感渲染----铅笔画滤镜 写在前面 使用深度图补充细节

我们前面在这里拿到铅笔的笔画六张下图,我们根据图片的亮度来选择纹理填充图画

【NPR】Unity3D非真实感渲染----铅笔画滤镜 写在前面 使用深度图补充细节

      填充色块的代码: 

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) ;
           

将上面的两幅图片逐个像素相乘可得出下图的效果:

【NPR】Unity3D非真实感渲染----铅笔画滤镜 写在前面 使用深度图补充细节

使用深度图补充细节

    漫画家绘制素描时线条不一定都是笔直的,线条的走向与物体表面的凹凸有关,弯曲会给人一种伪造的3D感觉。     关于深度图的使用请看这里,本来使用CameraDepthNormalsTexture来绘制表面更好,但我没能成功获取.........     原深度图:    

【NPR】Unity3D非真实感渲染----铅笔画滤镜 写在前面 使用深度图补充细节

    我们从现在开始给画的亮度填充时加入深度图的影响:

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) ;
           

最终得到的效果如下,加入了深度的影响铅笔的立体感更明显些:

【NPR】Unity3D非真实感渲染----铅笔画滤镜 写在前面 使用深度图补充细节

      关于滤镜的使用请参考 【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 本人长期离线,欢迎任何提问

继续阅读