【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

在这里插入图片描述

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);
    }
    /// <summary>
    /// 时间插值
    /// </summary>
    /// <param name="time">插值时间</param>
    /// <param name="id">ID</param>
    /// <param name="action">返回方法</param>
    public void DoTime(float time, Action<float> action, string id = null)
    {

        IEnumerator coroutine;
        coroutine = DoTimeIE(time, action);
        StartCoroutine(coroutine);
    }
    IEnumerator DoTimeIE(float time, Action<float> 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"
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Unity中可以使用Shader来实现模型的切割效果,具体实现步骤如下: 1. 创建一个新Shader,命名为“CutoutShader”,并打开它。 2. 在Shader中添加以下代码: ``` Shader "Custom/CutoutShader" { Properties { _MainTex ("Texture", 2D) = "white" {} _SlicePos ("Slice Position", Range(0,1)) = 0.5 _SliceAxis ("Slice Axis", Vector) = (1,0,0,0) } SubShader { Tags {"Queue"="Transparent" "RenderType"="TransparentCutout"} LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; float4x4 unity_ObjectToWorld; float4x4 unity_WorldToObject; float4 _SliceAxis; float _SlicePos; sampler2D _MainTex; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } fixed4 frag (v2f i) : SV_Target { float4 worldPos = mul(unity_ObjectToWorld, float4(i.vertex.xyz, 1)); float3 slicePos = mul(unity_ObjectToWorld, float4(_SlicePos, _SlicePos, _SlicePos, 1)).xyz; float3 sliceAxis = normalize(mul(unity_ObjectToWorld, _SliceAxis)).xyz; float dist = dot(worldPos.xyz - slicePos, sliceAxis); clip(dist); return tex2D(_MainTex, i.uv); } ENDCG } } FallBack "Diffuse" } ``` 3. 在Inspector面板中,为Shader添加以下属性: - _MainTex:纹理贴图。 - _SlicePos:切割位置,取值范围为0~1。 - _SliceAxis:切割轴,可以是X轴、Y轴或Z轴。 4. 将Shader应用到需要切割的物体上。 5. 在脚本中,通过修改SlicePos和SliceAxis的值,可以实现切割效果。 至此,一个基本的模型切割Shader就完成了。需要注意的是,该Shader只支持平面切割,如果需要实现更复杂的切割效果,需要进一步修改Shader代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小生云木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值