unity-shader卡通渲染:描边,XRay透视,边缘外发光,卡通着色,色阶,离散化

先看效果,再上代码,最后知识点解释:
{–Xray基本原理就是:ZTest Great产生的作用
描边:法线外拓(把顶点沿着法线方向向外挤)
卡通着色颜色处理:产生色阶,颜色的离散化
轮廓外发光:确定外轮廓线在哪,再发光–}
卡通着色
(1)效果:
描边:
unity-shader卡通渲染:描边,XRay透视,边缘外发光,卡通着色,色阶,离散化_第1张图片边缘光:
unity-shader卡通渲染:描边,XRay透视,边缘外发光,卡通着色,色阶,离散化_第2张图片

Xray透视:
unity-shader卡通渲染:描边,XRay透视,边缘外发光,卡通着色,色阶,离散化_第3张图片

// float lerp(float a, float b, float w) {
//   return a(1-w) + b * w;
// }
// 上面是 lerp插值的公式:说白了,也就是一个混合公式,他们俗称插值, 只不过w相当于以第二个参数为源,第一个参数为目标。 直白点,就是把b向a上混合
Shader "Unlit/KaTong"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Diffuse("Diffuse",Color) = (1,1,1,1)
        _OutLineSize("Outline",Range(0,0.2))=0.1
        _OutLineColor("OutlineColor",Color)=(0,0,0,0)
        _Steps("diffuse Color devide to Steps",Range(1,30))=10
        _ToonEffectSize("ToonEffectSize",Range(0,1))=0.5
        ////渐进纹理
        //_RampTex("RampTex",2D) = "white"{}
        //边缘光
        _RimColor("RimColor",Color) =(0,0,0,0)
        _RimPower("RimPower",Range(0.00001,100))=1
        //Xray 透视
        _XRayColor("XRayColor",Color) = (1,1,1,1)
        _XRayPower("XrayPower",Range(0.0001,3))=1

    }
    SubShader
    {
        Tags { "Queue"="Geometry" "RenderType"="Opaque" }
        LOD 100
        Pass
        {
        	Tags { "Queue"="Geometry+1000" "RenderType"="Opaque" }
            Name "XRay"
            Tags{"ForceNoSjadowCasting"="true"}
            Blend SrcAlpha One
            ZWrite Off
            ZTest Greater

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc" 
            float4 _XRayColor;
            float _XRayPower;

            struct v2f{
                float4 pos : SV_POSITION;
                float3 worldViewDir:TEXCOORD0;
                float3 worldNormal:NORMAL;
            };
            v2f vert(appdata_base v){
                v2f o;
                o.pos = UnityWorldToClipPos(v.vertex);
                o.worldViewDir = ObjSpaceViewDir(v.vertex);
                o.worldNormal = v.normal;
                return o;
            }
            fixed4 frag(v2f i):SV_TARGET{
                float3 worldNormal = normalize(i.worldNormal);
                float3 worldViewDir = normalize(i.worldViewDir);
                float rim = 1-dot(worldNormal,worldViewDir);
                return _XRayColor * pow(rim,1/_XRayPower);
            }

            ENDCG

        }

        Pass
        {
            Name "OutLine"
            Cull Front
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            float _OutLineSize;
            float4 _OutLineColor;

            struct v2f{
                float4 vertex : SV_POSITION;
            };
            v2f vert(appdata_base v){
                v2f o;
                v.vertex += float4(v.normal,0) * _OutLineSize;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }
            fixed4 frag(v2f i) : SV_TARGET{
                return _OutLineColor;
            }
            ENDCG
        }

        Pass{
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
			#include "Lighting.cginc"

            struct v2f{
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 worldNormal : TEXCOORD1;
                float3 worldPos : TEXCOORD2;
            };
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _Diffuse;
            float _Steps;
            float _ToonEffectSize;
            float4 _RimColor;
            float _RimPower;
            v2f vert(appdata_base v){
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.worldPos = mul(unity_ObjectToWorld,v.vertex);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
                return o;
            }
            fixed4 frag(v2f i):SV_TARGET{
                float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
                float4 albedo = tex2D(_MainTex,i.uv);
                float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
                float3 worldNormal = normalize(i.worldNormal);
                //卡通颜色分层 方式1:
                float difLight = dot(worldLightDir,worldNormal) * 0.5 + 0.5;
                //颜色平滑在【0,1】之间
                difLight = smoothstep(0,1,difLight);
                // 颜色离散化 分成_Steps层
                float toon = floor(difLight * _Steps)/_Steps;
                //就是把toon向difLight上混合
                difLight = lerp(difLight,toon,_ToonEffectSize);
                fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * difLight;
                ////卡通颜色分层 方式2:
                //渐进纹理颜色值
                //float difLight = dot(worldLightDir,worldNormal) * 0.5 + 0.5;
				//fixed4 rampColor = tex2D(_RampTex, fixed2(difLight,difLight));:
                //fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * rampColor.rgb;

                //边缘光 首先要确定边缘的位置:worldNormal和 viewDir 垂直时,才是边缘,即:dot(worldNormal,viewDir) = 0
                float3 viewDir = UnityWorldSpaceViewDir(i.worldPos);
                float rim = 1- dot(worldNormal,viewDir);
                float3 rimColor = _RimColor * pow(rim,1/_RimPower);
                return fixed4(ambient + diffuse + rimColor,1);
            }
            ENDCG
        }

    }
}

用到的知识点:
1.渲染队列:在此shader中共用3个pass,第一个XRay透视 pass的Tags { “Queue”=“Geometry+1000” }是3个当中最后一个渲染
unity-shader卡通渲染:描边,XRay透视,边缘外发光,卡通着色,色阶,离散化_第4张图片
2.深度测试和深度写入(默认ZWrite on):
默认为ZTest LEqual
ZTest Less:深度小于当前缓存则通过
ZTest Greater:深度大于当前缓存则通过
ZTest LEqual:深度小于等于当前缓存则通过
ZTest GEqual:深度大于等于当前缓存则通过
ZTest Equal:深度等于当前缓存则通过
ZTest NotEqual:深度不等于当前缓存则通过
ZTest Always:不论如何都通过
ZTest Off等同于ZTest Always,关闭深度测试等于完全通过。
unity-shader卡通渲染:描边,XRay透视,边缘外发光,卡通着色,色阶,离散化_第5张图片3.透明度混合:开启混合,并设置混合因子。源颜色(该片元颜色)乘以SrcFactor,目标颜色(已经存在于颜色缓冲的颜色)会乘以DstFactor,然后把两者相加后在存入颜色缓冲区
unity-shader卡通渲染:描边,XRay透视,边缘外发光,卡通着色,色阶,离散化_第6张图片4.常用函数:
(1)lerp(a,b,w):说白了,也就是一个混合公式,插值, 只不过w相当于以第二个参数为源,第一个参数为目标。 就是把b向a上混合
//函数
float lerp(float a, float b, float w) {
return a(1-w) + b * w;
}

(2)smoothstep(a, b, x)可以用来生成0到1的平滑过渡.
https://blog.csdn.net/u010333737/article/details/828592465
5.其他:
漫反射,dot,pow等基本的就不再说了,多动手多思考!!!!!

你可能感兴趣的:(unity-shader卡通渲染:描边,XRay透视,边缘外发光,卡通着色,色阶,离散化)