【NPR】Unity3D非真实感渲染----铅笔画滤镜

来源:互联网 发布:音乐截取软件 for mac 编辑:程序博客网 时间:2024/04/29 21:13

写在前面

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

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

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 initializationvoid 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 framevoid Update () {if(curMaterial==null)enabled=false;}}

本项目所有源码在Here
本人长期离线,欢迎任何提问

0 0
原创粉丝点击