unity shader之——分割物体效果(着色器分割物体的方法)

在很多打斗游戏中,经常能看到物体被撕碎或者打破的效果,这种效果比较直观,可以通过分割一个网格来实现,即在原来网格基础上,再算出一个新的网格,本章将介绍一种通过着色器分割一个物体的方法。

一、分割一个物体的思路

1.1 我们需要什么样的信息

分隔一个物体,需要知道刀刃的碰触点和方向,这样就能确定一个剪切平面了。

其次,需要两个通道来渲染物体,这两个通道用同样的平面和方式剪切。

最后,需要构造一个平面,用来缝补被剪切的物体中出现的空洞,这个平面的法线应该沿剪切平面的方向,物体的正面正常渲染,物体的背面用于构成剪切之后填补的洞面。

1.2 脚本的帮助

需要脚本来传递剪切信息、方向和位置,在ClipObj.cs中实现:

public class ClipObj : MonoBehaviour {
	public Transform clipObj;
	public Material mat;
	// Use this for initialization
	void Start () {
	
	}
	
	// Update is called once per frame
	void Update () {
		Vector3 cpos = clipObj.position;
		Vector4 cnor = clipObj.up;
		mat.SetVector ("cPos",new Vector4(cpos.x,cpos.y,cpos.z,1) );//第四个元素为1,而不是0,可确保平移
		mat.SetVector ("cNormal",new Vector4(cnor.x,cnor.y,cnor.z,0) );
	}
}

二、在着色器中剪切一个物体

对物体的剪切是在ClipObj.shader中实现的。这个着色器有两个通道,第一个通道为CullFront,在第一个vertex函数中使用剪切方向和顶点法线。计算了剪切出来的洞口平面的光照,将剪切点的位置与方向变换到物体的模型空间内,这是为了方便下一步的计算。

然后在fragment函数中,对每一个像素点确定剪切点到像素点的方向,并计算这个方向和剪切方向的矢量的点积。如果点积小于0,就丢弃掉。

在第二个cull back的通道中使用和第一个通道相同的剪切,使用正常的光照计算。代码如下:

Shader "Tut/Shader/ClipObj" {
	Properties {
	
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		pass
		{
		Tags{"LightMode"="ForwardBase"}
		Cull Front
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#include "UnityCG.cginc"
		#pragma target 3.0
		
		struct v2f{
			float4 pos:SV_POSITION;
			float vc:TEXCOORD0;
			float3 px:TEXCOORD1;
			float3 cp:TEXCOORD2;
			float3 cn:TEXCOORD3;
		};
		float4 cPos;//world Position
		float4 cNormal;
		v2f vert(appdata_full i)
		{
			v2f o;
			o.pos=UnityObjectToClipPos(i.vertex);
			float3 ld=ObjSpaceLightDir(i.vertex);
			ld=normalize(ld);
			//对于填补的洞口,使用剪切方向作为法线,计算光照
			o.vc=max(0,dot(cNormal.xyz,ld));
			o.px=i.vertex/i.vertex.w;
			//float4 wPos=
			o.cp=mul(unity_WorldToObject,cPos).xyz;
			o.cn=mul(unity_WorldToObject,cNormal).xyz;
			
			return o;
		}
		
		float4 frag(v2f i):COLOR
		{
			float3 dir=i.cp-i.px;
			float c=dot(dir,i.cn);
			clip(c);
			
			return float4(i.vc,i.vc,i.vc,0);
		}
		ENDCG
		}
		pass
		{
		Tags{"LightMode"="ForwardBase"}
		Cull Back
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#include "UnityCG.cginc"
		#pragma target 3.0
		
		struct v2f{
			float4 pos:SV_POSITION;
			float vc:TEXCOORD0;
			float3 px:TEXCOORD1;
			float3 cp:TEXCOORD2;
			float3 cn:TEXCOORD3;
		};
		float4 cPos;//world Position
		float4 cNormal;
		v2f vert(appdata_full i)
		{
			v2f o;
			o.pos=UnityObjectToClipPos(i.vertex);
			float3 ld=ObjSpaceLightDir(i.vertex);
			ld=normalize(ld);
			o.vc=max(0,dot(i.normal,ld));//正常计算光照
			o.px=i.vertex/i.vertex.w;
		
			o.cp=mul(unity_WorldToObject,cPos).xyz;
			o.cn=mul(unity_WorldToObject,cNormal).xyz;
			
			return o;
		}
		
		float4 frag(v2f i):COLOR
		{
			float3 dir=i.cp-i.px;
			float c=dot(dir,i.cn);
			clip(c);
			
			return float4(i.vc,i.vc,i.vc,0);
		}
		ENDCG
		}
	} 
	FallBack "Diffuse"
}

版权声明:本文为CSDN博主「小橙子0」的原创文章,
遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cgy56191948/article/details/103716705

推荐阅读