Unity CG着色器实战

卡通风格

  1. 先一个Pass只渲染背面,黑色,沿法线膨胀,做轮廓线效果;

  2. 正式渲染Pass,漫反射采样一个逐渐变暗的纹理,做出硬边明暗。高光反射和一个阈值比较,大于则直接显示高光颜色。

    Shader "My/Toon"
    {
    Properties
    {
    _Color ("Color", Color) =(1,1,1,1)
    _SpeColor("SpeColor",Color)=(1,1,1,1)
    _SpecThreshold("SpecThreshold",Range(0.1,1))=1
    _MainTex("MainTex",2D)="white"{}
    _ShadeTex("ShadeTex",2D)="white"{}
    _OutlineWidth("OutlineWidth",Range(0.001,0.1))=0.01
    _OutlineCol("OutlineColor",Color)=(0,0,0,1)
    [Enum(UnityEngine.Rendering.CullMode)]_Cull("Cull",Float)=0
    }
    SubShader
    {
    Tags { "RenderType"="TransparentCutout""Queue"="AlphaTest"}
    LOD 100
    Pass{
    Name "Outline"
    Cull Front

    复制代码
             CGPROGRAM
             #pragma vertex vert
             #pragma fragment frag
             #include "UnityCG.cginc"
             struct v2f
             {
                 float4 vertex: SV_POSITION;
             };
             float _OutlineWidth;
             fixed4 _OutlineCol;
             v2f vert(appdata_base v){
                 v2f o;
                 v.vertex.xyz+= normalize(v.normal)* _OutlineWidth;
                 o.vertex= UnityObjectToClipPos(v.vertex);
                 return o;
             }
             fixed4 frag(v2f i): SV_Target{
                 return _OutlineCol;
             }
             ENDCG
         }
         Pass
         {
             Name "Main"
             Tags{"LightMode" = "ForwardBase"}
             Cull [_Cull]
             Blend SrcAlpha OneMinusSrcAlpha
             CGPROGRAM
             #pragma vertex vert
             #pragma fragment frag
             #pragma multi_compile_fwdbase
             #include "UnityCG.cginc"
             #include "Lighting.cginc"
             #include "AutoLight.cginc"
             struct appdata
             {
                 float4 vertex : POSITION;
                 float3 normal : NORMAL;
                 float2 uv:TEXCOORD0;
             };
    
             struct v2f
             {
                 float4 pos : SV_POSITION;
                 float2 uv:TEXCOORD0;
                 float3 worldPos: TEXCOORD1;
                 float3 worldNormal: TEXCOORD2;
                 float3 viewDir: TEXCOORD3;
                 float3 lightDir: TEXCOORD4;
                 SHADOW_COORDS(5)
             };
             fixed4 _Color;
             fixed4 _SpeColor;
             float _SpecThreshold;
             sampler2D _MainTex;
             float4 _MainTex_ST;
             sampler2D _ShadeTex;
             v2f vert (appdata v)
             {
                 v2f o;
                 o.pos = UnityObjectToClipPos(v.vertex);
                 o.worldNormal=normalize(UnityObjectToWorldNormal(v.normal));
                 
                 o.lightDir=-normalize(_WorldSpaceLightPos0.xyz);
                 o.worldPos=mul(unity_ObjectToWorld,v.vertex);
                 o.viewDir=normalize(_WorldSpaceCameraPos-o.worldPos);
    
                 TRANSFER_SHADOW(o);
                 o.uv=v.uv;
                 return o;
             }
    
             fixed4 frag (v2f i) : SV_Target
             {
                 fixed4 texCol=tex2D(_MainTex,i.uv);
                 //漫反射
                 float3 lightPos=normalize(_WorldSpaceLightPos0.xyz);
                 fixed diff=dot(i.worldNormal,lightPos)*0.5+0.5;
                 UNITY_LIGHT_ATTENUATION(atten,i,i.worldPos);
                 diff*=atten;
                 fixed4 shadeCol=tex2D(_ShadeTex,float2(diff,0));
                 //高光
                 float3 reflDir=reflect(i.lightDir,i.worldNormal);
                 float spec=step(_SpecThreshold ,dot(reflDir,i.viewDir));
                 fixed3 color=_Color.rgb* texCol.rgb*(UNITY_LIGHTMODEL_AMBIENT+ shadeCol)
                 +_SpeColor.rgb* spec;
                 return fixed4(color,texCol.a);
                 //return UNITY_LIGHTMODEL_AMBIENT;
             }
             ENDCG
         }
     }
     Fallback "Diffuse"

    }

脸的下部有点黑,可以加一个漫反射明暗到渐变贴图u的系数,控制漫反射变黑的阈值。原神的效果比这个更亮。这个有点纸模感。

消融效果

  1. uv采样柏林噪声贴图,小于阈值则clip()不渲染;
复制代码
Shader "My/Melt"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _NoiseTex("NoiseTex",2D)=""{}
        _EdgeTex("EdgeTex",2D)=""{}
        _EdgeWidth("EdgeWidth",Range(0,1))=0.01
        _MeltThre("MeltThreshold",Range(0,1))=0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };
            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _NoiseTex;
            sampler2D _EdgeTex;
            fixed _EdgeWidth;
            fixed _MeltThre;
            v2f vert (appdata_base v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed no= tex2D(_NoiseTex,i.uv);
                clip(no- _MeltThre);
                //噪声离阈值的差小于edge宽度时,开始显示边缘;
                //把差值相对于edge宽度的比例转换到0-1,用于采样贴图
                fixed edgeU=1- smoothstep(0,_EdgeWidth,no- _MeltThre);
                fixed4 edgeCol= tex2D(_EdgeTex,fixed2(edgeU,0.5));
                fixed4 col = tex2D(_MainTex, i.uv);
                return lerp(col, edgeCol,edgeU);
            }
            ENDCG
        }
    }
}

水面

复制代码
Shader "My/Water"
{
    Properties{
        _MainTex("MainTex",2D)=""{}
        _NormalTex("NormalTex",2D)=""{}
        _Cube("Cubemap",Cube)=""{}
        _Distortion("Distortion",Range(0,1))=0
        _XSpeed("XSpeed",Range(-0.1,0.1))=0.01
        _YSpeed("YSpeed",Range(-0.1,0.1))=0.01
        _Fresnel("Fresnel",Range(0,1))=1
    }
    SubShader{
        Tags{"RenderType"="Opaque""Queue"="Transparent"}
        GrabPass{}
        Pass{
            Tags{"LightMode"="ForwardBase"}
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            sampler2D _NormalTex;
            float4 _NormalTex_ST;
            samplerCUBE _Cube;
            sampler2D _GrabTexture;//GrabPass捕获的图像,默认名
            float _Distortion;
            fixed _XSpeed;
            fixed _YSpeed;
            float _Fresnel;
            struct v2f
            {
                float4 pos:SV_POSITION;
                float4 grabPos:TEXCOORD0; 
                float4 uv:TEXCOORD1;
                float4 TtoW0: TEXCOORD3;
                float4 TtoW1: TEXCOORD4;
                float4 TtoW2: TEXCOORD5;
            };
            v2f vert(appdata_full v){
                v2f o;
                o.pos= UnityObjectToClipPos(v.vertex);
                o.grabPos= ComputeScreenPos(o.pos);
                o.uv.xy=v.texcoord.xy* _MainTex_ST.xy+ _MainTex_ST.zw;
                o.uv.zw=v.texcoord.xy* _NormalTex_ST.xy+ _NormalTex_ST.zw;
                float3 worldNormal= UnityObjectToWorldNormal(v.normal);
                fixed3 worldPos=mul(unity_ObjectToWorld,v.vertex).xyz;
                //
                float3 worldTan= UnityObjectToWorldDir(v.tangent);
                float3 worldBinormal= cross(normalize(worldTan),normalize(worldNormal))*v.tangent.w;
                
                o.TtoW0=float4(worldTan.x,worldBinormal.x,worldNormal.x,worldPos.x);
                o.TtoW1=float4(worldTan.y,worldBinormal.y,worldNormal.y,worldPos.y);
                o.TtoW2=float4(worldTan.z,worldBinormal.z,worldNormal.z,worldPos.z);
                return o;
            }
            fixed4 frag(v2f i):SV_Target{
                float3 worldPos=float3(i.TtoW0.w,i.TtoW1.w,i.TtoW2.w);
                fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
                //float4 normal= tex2D(_NormalTex,i.uv.zw);
                ////法线贴图的法线在切线空间
                //float3 tanNormal=UnpackNormal(normal);
                float2 speed= _Time.y*float2( _XSpeed,_YSpeed);
                float4 packNormal= tex2D(_NormalTex,i.uv.zw+ speed);
                fixed3 bump1= UnpackNormal(packNormal).rgb;
                packNormal= tex2D(_NormalTex,i.uv.zw- speed);
                fixed3 bump2= UnpackNormal(packNormal).rgb;
                fixed3 bump= normalize( bump1+bump2);
                ////法线贴图的法线在世界
                float3 worldNormal =
                float3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump));

                fixed3 albedo = tex2D(_MainTex, i.uv.xy);
                float3 refl= reflect(-viewDir,worldNormal);
                //兰伯特
                //fixed3 lambertColor = _LightColor0.rgb * albedo.rgb * max(0, dot(worldNormal, normalize(_WorldSpaceLightPos0.xyz)));
                //半角向量
                //float3 halfA = normalize(normalize(viewDir) + normalize(_WorldSpaceLightPos0.xyz));
                //高光反射
                //fixed3 specularColor = _LightColor0.rgb* pow(max(0, dot(worldNormal, halfA)), _SpecularNum);
                fixed4 reflCol= texCUBE(_Cube,refl)*tex2D(_MainTex,i.uv);
                float2 offset= bump.xy*_Distortion;
                i.grabPos.xy= offset*i.grabPos.z+ i.grabPos.xy;
                fixed2 screenUV=(i.grabPos.xy+offset)/i.grabPos.w;
                fixed4 grabCol= tex2D(_GrabTexture,screenUV);
                fixed fresnel= _Fresnel+(1- _Fresnel)*
                pow((1-dot(normalize(viewDir),normalize(worldNormal))),5);
                float4 color=reflCol*(1-fresnel)+grabCol*fresnel;
                return color;
            }
            ENDCG
        }
    }
}
相关推荐
Allen747416 小时前
ComfyUI 自动化生产 3D资产 工作流笔记
图像处理·opencv·unity·自然语言处理·3d模型生成·confyui
nnsix19 小时前
Unity Windows11 打字中文显示不出来输入法的候选框
unity
adogai1 天前
unity mcp接入 实现一句话生成游戏!
游戏·unity·游戏引擎
mxwin1 天前
Unity Shader 逐像素光照 vs 逐顶点光照性能与画质的权衡策略
unity·游戏引擎·shader·着色器
CDN3601 天前
游戏盾导致 Unity/UE 引擎崩溃的主要原因排查?
游戏·unity·游戏引擎
mxwin1 天前
Unity URP 全局光照 (GI) 完全指南 Lightmap 采样与实时 GI(光照探针、反射探针)的 Shader 集成
unity·游戏引擎·shader·着色器
mxwin1 天前
Unity URP 溶解效果基于噪声纹理与 clip 函数实现物体渐隐渐显
unity·游戏引擎·shader
CheerWWW2 天前
GameFramework——Download篇
笔记·学习·unity·c#
mxwin2 天前
Unity URP 下的 Early-Z / Depth Prepass 解决复杂片元着色器造成的 Overdraw 问题
unity·游戏引擎·着色器
mxwin2 天前
Unity Shader 顶点色:利用模型顶点颜色传递渲染数据
unity·游戏引擎·shader