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





