返回
Featured image of post 卡通积雪场景

卡通积雪场景

核心

积雪方向和法线进行点击,如果大于积雪厚度值则改变该片元的输出颜色为雪的颜色

效果图

Shader "Unlit/020"
{
    Properties
    {
        _MainTex ("纹理", 2D) = "white" {}
		_Diffuse("漫反射",Color) = (1,1,1,1)

		_BumpMap("法线贴图",2D) = "while"{}
		_BumpScale("法线强度",float) = 1

		_Outline("轮廓粗细", Range(0,0.2)) = 0.1 
		_OutlineColor("轮廓颜色", Color) = (0,0,0,0)
		_Step("离散化",Range(1,30))=1
		_ToonEffect("卡通效果",Range(0,1))=0.5

		_Snow("积雪厚度",Range(0,1)) = 0.5
		_SnowColor("积雪的颜色",Color) = (1,1,1,1)
		_SnowDir("积雪的方向",Vector) = (0,1,0)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

		//调用上章所用到的描边ShaderPass进行描边
		UsePass "Unlit/019/Outline"

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
			
            //宏开关设置
	    #pragma multi_compile __ SNOW_ON

            #include "UnityCG.cginc"
            #include "Lighting.cginc"

          
            struct v2f
            {
		float4 vertex : SV_POSITION;
                float4 uv : TEXCOORD0;
                float4 T2W0 : TEXCOORD1;
	        float4 T2W1 : TEXCOORD2;
                float4 T2W2 : TEXCOORD3;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
	    fixed4 _Diffuse;
            float _Step;
	    float _ToonEffect;
	    sampler2D _BumpMap;
	    float4 _BumpMap_ST;
	    float _BumpScale;
	    float _Snow;
	    float4 _SnowColor;
	    float4 _SnowDir;

            v2f vert (appdata_tan v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
		o.uv.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);
				
				//求出世界(坐标\法线\副法线\切线
				fixed3 worldPos = mul (unity_ObjectToWorld,v.vertex);
				fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
				fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
				fixed3 worldBinormal = cross(worldNormal,worldTangent) * v.tangent.w;
				
				//切线空间转世界空间矩阵
				o.T2W0 = float4(worldTangent.x,worldBinormal.x,worldNormal.x,worldPos.x);
				o.T2W1 = float4(worldTangent.y,worldBinormal.y,worldNormal.y,worldPos.y);
				o.T2W2 = float4(worldTangent.z,worldBinormal.z,worldNormal.z,worldPos.z);

                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT;
				//采样
				fixed4 albedo = tex2D(_MainTex,i.uv);

				//世界坐标
				float3 worldPos = float3(i.T2W0.w,i.T2W1.w,i.T2W2.w);

				//光源方向和视角方向
				fixed3 lightDir = UnityWorldSpaceLightDir(worldPos);
				fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));

				//法线贴图
				fixed4 packedNormal = tex2D(_BumpMap,i.uv.zw);
				//切线空间法线
				fixed3 tangentNormal = UnpackNormal(packedNormal);
				tangentNormal.xy *= _BumpScale;
				//转换成世界坐标法线
				fixed3 worldNormal = normalize(float3(dot(i.T2W0.xyz, tangentNormal),dot(i.T2W1.xyz, tangentNormal),dot(i.T2W2.xyz, tangentNormal)));


				//半罗伯特模型
				float difLight= dot(lightDir,worldNormal)* 0.5+0.5;
				difLight = smoothstep(0,1,difLight);
				
				//离散化
				float toon = floor(difLight * _Step)/_Step;
				difLight = lerp(difLight, toon, _ToonEffect);

				//光照模型
				fixed3 diffuse = _LightColor0.rgb * albedo * _Diffuse.rgb * difLight;

				fixed4 color = fixed4 (ambient + diffuse,1); 

				//宏开关控制
				#if SNOW_ON
				//积雪
				if(dot(worldNormal,_SnowDir.xyz)>lerp(1,-1,_Snow))
				{
					color.rgb = _SnowColor.rgb;
				}
				#endif

                return color;
            }
            ENDCG
        }
    }
}
  • 宏控制代码 该脚本需要放在项目Editor文件夹中
using UnityEditor;
using UnityEngine;

public class Tools : MonoBehaviour
{
    private static string SNOW_ON = "SNOW_ON";

    [MenuItem("Tools/Shader/开启雪景宏")]
    public static void OpenRimlight()
    {
        if (Shader.IsKeywordEnabled(SNOW_ON))
        {
            Shader.DisableKeyword(SNOW_ON);
        }
        else
        {
            Shader.EnableKeyword(SNOW_ON);
        }
    }
}
Licensed under CC BY-NC-SA 4.0
0