这是用6个面来切割模型shader,当然稍加修改可以支持n(n>=1)个面,在c#代码中分别为pPoint和pNormal参数赋值,pPoint传入平面的世界坐标,pNormal传入该平面的法线。考虑到性能,光照模型加在了顶点程序中。
Shader "Custom/6PlaneClipShader"
{
Properties{
_Diffuse("Diffuse", Color) = (1,1,1,1)
_MainTex("Base 2D", 2D) = "white"{}
}
SubShader
{
Pass
{
Tags{ "RenderType" = "Opaque" }
CGPROGRAM
#include "Lighting.cginc"
fixed4 _Diffuse;
sampler2D _MainTex;
float4 _MainTex_ST;
float4 pPoint[6];
float4 pNormal[6];
struct a2v
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct v2f
{
float4 pos : SV_POSITION;
fixed4 color : COLOR;
float2 uv : TEXCOORD1;
float4 VertPos:TEXCOORD2;
};
bool effectiveRange(float3 pos)
{
pos = mul(unity_ObjectToWorld, float4(pos, 1));
for (int i = 0; i < 6; i++) {
float3 dir = normalize(pos - pPoint[i].xyz);
//如果平面内任意点指向该模型顶点的向量与法线夹角为锐角,则保留该点
if (dot(dir, normalize(pNormal[i].xyz))< 0) {
return false;
}
}
return true;
}
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.VertPos = v.vertex;
//------------------------
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
float3 worldNormal = mul(unity_WorldToObject,v.normal);
worldNormal = normalize(worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 lambert = 0.5 * dot(worldNormal, worldLightDir)+0.5;
o.color = fixed4(lambert * _Diffuse.xyz * _LightColor0.xyz + ambient* _Diffuse.xyz, 1.0);
//---------该部分实现halfLambert光照模型
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
//配置Tilling
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = fixed4(0,0,0,0);
if (effectiveRange(i.VertPos))
{
col= i.color * tex2D(_MainTex, i.uv);
}
else
{
discard;
}
return col;
}
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
FallBack "Diffuse"
}
C#代码部分:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SetAllPlane : MonoBehaviour {
public Transform[] plane;
void Start () {
Vector4[] point = new Vector4[6];
Vector4[] normal = new Vector4[6];
for (int i=0;i<plane.Length;i++)
{
point[i] = plane[i].position;
normal[i] = plane[i].forward;
}
GetComponent<MeshRenderer>().material.SetVectorArray("pPoint", point);
GetComponent<MeshRenderer>().material.SetVectorArray("pNormal", normal);
}
}