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