【unity】模型裁剪shader(建筑生长动画)

【unity】模型裁剪shader(建筑生长动画)

思路

使用的核心方法是clip,当传入正值时渲染,传入负值时不渲染。定义一个裁剪向量,使用裁剪向量和模型点点乘,如果模型点和裁剪向量是同一个方向,点乘为正,相反为负。

shader源码

Shader "SongShaderDemo/CutOffWorld"
{
    Properties
    {
       _MainTex("Texture", 2D) = "white" {}
       _CutValue("切割范围:",Float) = 0
      _CutDirection("切割方向",Vector) = (0, 1, 0, 0)
      _CutDistance("切割距离",Float) = 1000
       _LightIntensity("灯光强度",Float) = 1
    }
    SubShader
    {
       Tags { "RenderType" = "Opaque" "LigthMode" = "ForwarBase"}
        LOD 100

        Pass
        {
            Cull Off
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Lighting.cginc "
            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal: NORMAL;//存储法线的盒子
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float3  worldPos  : TEXCOORD1;
                float3 wNormal:TEXCOORD6;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _CutValue;
            float _CutDistance;
            float4 _CutDirection;
            float _LightIntensity;
            v2f vert (appdata v)
            {
                v2f o;
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.wNormal = UnityObjectToWorldNormal(v.normal);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                //_WorldSpaceLightPos0 unity提供的灯光向量
                float3 L = normalize(_WorldSpaceLightPos0);
                float3 N = normalize(i.wNormal);
                float halfLam = dot(L, N) * 0.5 + 0.75;
                //_LightColor0.rgb unity提供的灯光强度
                float3 diffLight = halfLam * _LightColor0.rgb*_LightIntensity;
                fixed4 diffColor = fixed4(diffLight.rgb, 1);
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                float3 cutDirection = normalize(_CutDirection.xyz);//切割向量
                float3 curCenter = (cutDirection * (_CutValue - 0.5) * _CutDistance);//切割的原点,在切割的向量上移动
                float3 targetVer = i.worldPos - curCenter;//切割原点到模型点上的向量
                float angel =- dot(cutDirection,normalize(targetVer));//切割向量和targetVer点乘,正则同方向,父则反方向
                clip(angel);//反方向剔除
                return col* diffColor;
            }
            ENDCG
        }
    }
}

使用Shader Graphs

【unity】模型裁剪shader(建筑生长动画)_第1张图片

shaderGraphs设置

在Gragh Inspector里勾选Alpha Cilpping

在Fragment里Alpha Clip Threshold设置为0(Alpha>=Alpha Clip Threshold阈值,那么显示图像,如果小于,则裁剪掉小于的部分

demo

using System;
using System.Collections;
using UnityEngine;

public class MatManager : MonoBehaviour
{
    public float High;//裁剪距离
    public Material CutMaterial;//裁剪材质
    void Start()
    {
        DoTime(4, SetCutHigh);
    }
    void  SetCutHigh(float Time)
    {
        CutMaterial.SetFloat("_CutValue", High* Time);
    }
    /// 
    /// 时间插值
    /// 
    /// 插值时间
    /// ID
    /// 返回方法
    public void DoTime(float time, Action action, string id = null)
    {

        IEnumerator coroutine;
        coroutine = DoTimeIE(time, action);
        StartCoroutine(coroutine);
    }
    IEnumerator DoTimeIE(float time, Action action = null)
    {
        float t = 0;
        while (t < 1)
        {
            t += Time.deltaTime / time;
            if (action != null)
            {
                action(t);
            }
            t = t > 1 ? 1 : t;
            yield return null;
        }
        action(1);
    }
}

补充(自身模型空间的裁剪)

Shader "SongShaderDemo/CutOffObject"
{
	Properties
	{
	   _MainTex("Texture", 2D) = "white" {}
	   _CutValue("切割范围:",Float) = 0
	  _CutDirection("切割方向",Vector) = (0, 0, 0, 0)
	  _CutDistance("切割距离",Float) = 1
      _LightIntensity("灯光强度",Float) = 1
	}
		SubShader
	   {
		   Tags { "RenderType" = "Opaque" "LigthMode" = "ForwarBase"}
		   LOD 100
		  // Blend SrcAlpha OneMinusSrcAlpha

		ZWrite On
		Pass
		{
		Cull Off
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

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

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
				float3 normal: NORMAL;//存储法线的盒子
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				float4 vertex : SV_POSITION;
				float3  worldPos  : TEXCOORD1;
				float3 center:TEXCOORD2;
				float3 wNormal:TEXCOORD6;
			};

			sampler2D _MainTex;
			float4 _MainTex_ST;
			float _CutValue;
			float _CutDistance;
			float _LightIntensity;
			float4 _CutDirection;
			v2f vert(appdata v)
			{
				v2f o;
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				//得到中心点
				o.center = float3(unity_ObjectToWorld[0].w, unity_ObjectToWorld[1].w, unity_ObjectToWorld[2].w);
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				o.wNormal = UnityObjectToWorldNormal(v.normal);
				return o;
			}

			fixed4 frag(v2f i) : SV_Target
			{
				//_WorldSpaceLightPos0 unity提供的灯光向量
				float3 L = normalize(_WorldSpaceLightPos0);
				float3 N = normalize(i.wNormal);
				float halfLam = dot(L, N)*0.5 + 0.75;
				//_LightColor0.rgb unity提供的灯光强度
				float3 diffLight = halfLam * _LightColor0.rgb*_LightIntensity;
				fixed4 diffColor = fixed4(diffLight.rgb, 1);
				// sample the texture
				fixed4 col = tex2D(_MainTex, i.uv);

			float3 cutDirection = normalize(_CutDirection.xyz);//切割向量
			float3 curCenter = i.center + (cutDirection*(_CutValue - 0.5)*_CutDistance);//切割的原点,在切割的向量上移动
			float3 targetVer = i.worldPos - curCenter;//切割原点到模型点上的向量
			float angel = dot(normalize(targetVer), cutDirection);//切割向量和targetVer点乘,正则同方向,父则反方向
			clip(angel);//反方向剔除
	
			return col * diffColor;
			}
			ENDCG
		}
		

	   }
		  Fallback "Transparent/VertexLit"
}

你可能感兴趣的:(Unity,unity,游戏引擎)