这是用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); } }