【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"
}