unity 溶解贴花编辑器

来源:互联网 发布:2网络作家富豪榜 编辑:程序博客网 时间:2024/04/29 01:03

实现的效果:

       游戏中,比如溅水花到墙壁上,然后水渍在墙上慢慢消融的这种效果

实现机制:

        首先需要把水花贴到墙壁,这里需要用到贴花的知识。然后,实现贴花消融的效果,需要一个溶解的shader。在贴花的实现中,有几种方法,一种是利用后期的方法,通过深度buff,检测到可以看到的物体的表面,然后对这些模型重新着色,这种方法的好处是可以获取更加逼真自然,也不容易受物体表面凹凸的影响,效果比较好。 另一种方法,是不用深度buffer,而是获取物体表面的plogins,重新构建mesh,然后对这个mesh赋予特定texture的纹理。后一种方法在unity 中似乎比较常见。端游中人物脚底光环等贴花经常用到的是第一种方法。 本文在unity中的是用第二种方法。


实现具体方法:


       定义decal,其中含material, sprite。 绘制的时候使用 drawspritelist

public Material material;public Sprite sprite;public float maxAngle = 90.0f;public float pushDistance = 0.009f;public LayerMask affectedLayers = -1;  // 此处的layer 是用于后面检测构建meshvoid OnDrawGizmosSelected() {Gizmos.matrix = transform.localToWorldMatrix;Gizmos.DrawWireCube( Vector3.zero, Vector3.one );}public Bounds GetBounds() {Vector3 size = transform.lossyScale;Vector3 min = -size/2f;Vector3 max =  size/2f;Vector3[] vts = new Vector3[] {new Vector3(min.x, min.y, min.z),new Vector3(max.x, min.y, min.z),new Vector3(min.x, max.y, min.z),new Vector3(max.x, max.y, min.z),new Vector3(min.x, min.y, max.z),new Vector3(max.x, min.y, max.z),new Vector3(min.x, max.y, max.z),new Vector3(max.x, max.y, max.z),};for(int i=0; i<8; i++) {vts[i] = transform.TransformDirection( vts[i] );}min = max = vts[0];foreach(Vector3 v in vts) {min = Vector3.Min(min, v);max = Vector3.Max(max, v);}return new Bounds(transform.position, max-min);}

       创建贴花的过程

private void BuildDecal(Decal decal) {MeshFilter filter = decal.GetComponent<MeshFilter>();if(filter == null) filter = decal.gameObject.AddComponent<MeshFilter>(); //meshfilter is a class to access mesh of a meshfilterif(decal.GetComponent<Renderer>() == null) decal.gameObject.AddComponent<MeshRenderer>(); //render mesh inserted in meshfilterdecal.GetComponent<Renderer>().material = decal.material;    //设置mesh的材质                decal.material.SetFloat("DissAmount", 0.5f);if(decal.material == null || decal.sprite == null) {filter.mesh = null;return;}affectedObjects = GetAffectedObjects(decal.GetBounds(), decal.affectedLayers);foreach(GameObject go in affectedObjects) {DecalBuilder.BuildDecalForObject( decal, go );}DecalBuilder.Push( decal.pushDistance );Mesh mesh = DecalBuilder.CreateMesh();if(mesh != null) {mesh.name = "DecalMesh";filter.mesh = mesh;}}
为某个对象创建贴花,主要是创建顶点,发现以及纹理坐标;

private static List<Vector3> bufVertices = new List<Vector3>();private static List<Vector3> bufNormals = new List<Vector3>();private static List<Vector2> bufTexCoords = new List<Vector2>();private static List<int> bufIndices = new List<int>();public static void BuildDecalForObject(Decal decal, GameObject affectedObject) {Mesh affectedMesh = affectedObject.GetComponent<MeshFilter>().sharedMesh;if(affectedMesh == null) return;float maxAngle = decal.maxAngle;Plane right = new Plane( Vector3.right, Vector3.right/2f );Plane left = new Plane( -Vector3.right, -Vector3.right/2f );Plane top = new Plane( Vector3.up, Vector3.up/2f );Plane bottom = new Plane( -Vector3.up, -Vector3.up/2f );Plane front = new Plane( Vector3.forward, Vector3.forward/2f );Plane back = new Plane( -Vector3.forward, -Vector3.forward/2f );Vector3[] vertices = affectedMesh.vertices;int[] triangles = affectedMesh.triangles;int startVertexCount = bufVertices.Count;Matrix4x4 matrix = decal.transform.worldToLocalMatrix * affectedObject.transform.localToWorldMatrix;for(int i=0; i<triangles.Length; i+=3) {int i1 = triangles[i];int i2 = triangles[i+1];int i3 = triangles[i+2];Vector3 v1 = matrix.MultiplyPoint( vertices[i1] );Vector3 v2 = matrix.MultiplyPoint( vertices[i2] );Vector3 v3 = matrix.MultiplyPoint( vertices[i3] );Vector3 side1 = v2 - v1;Vector3 side2 = v3 - v1;Vector3 normal = Vector3.Cross(side1, side2).normalized;if( Vector3.Angle(-Vector3.forward, normal) >= maxAngle ) continue;DecalPolygon poly = new DecalPolygon( v1, v2, v3 );poly = DecalPolygon.ClipPolygon(poly, right);if(poly == null) continue;poly = DecalPolygon.ClipPolygon(poly, left);if(poly == null) continue;poly = DecalPolygon.ClipPolygon(poly, top);if(poly == null) continue;poly = DecalPolygon.ClipPolygon(poly, bottom);if(poly == null) continue;poly = DecalPolygon.ClipPolygon(poly, front);if(poly == null) continue;poly = DecalPolygon.ClipPolygon(poly, back);if(poly == null) continue;AddPolygon( poly, normal );}GenerateTexCoords(startVertexCount, decal.sprite);}private static void AddPolygon(DecalPolygon poly, Vector3 normal) {int ind1 = AddVertex( poly.vertices[0], normal );for(int i=1; i<poly.vertices.Count-1; i++) {int ind2 = AddVertex( poly.vertices[i], normal );int ind3 = AddVertex( poly.vertices[i+1], normal );bufIndices.Add( ind1 );bufIndices.Add( ind2 );bufIndices.Add( ind3 );}}private static int AddVertex(Vector3 vertex, Vector3 normal) {int index = FindVertex(vertex);if(index == -1) {bufVertices.Add( vertex );bufNormals.Add( normal );index = bufVertices.Count-1;} else {Vector3 t = bufNormals[ index ] + normal;bufNormals[ index ] = t.normalized;}return (int) index;}private static int FindVertex(Vector3 vertex) {for(int i=0; i<bufVertices.Count; i++) {if( Vector3.Distance(bufVertices[i], vertex) < 0.01f ) {return i;}}return -1;}private static void GenerateTexCoords(int start, Sprite sprite) {Rect rect = sprite.rect;rect.x /= sprite.texture.width;rect.y /= sprite.texture.height;rect.width /= sprite.texture.width;rect.height /= sprite.texture.height;for(int i=start; i<bufVertices.Count; i++) {Vector3 vertex = bufVertices[i];Vector2 uv = new Vector2(vertex.x+0.5f, vertex.y+0.5f);uv.x = Mathf.Lerp( rect.xMin, rect.xMax, uv.x );uv.y = Mathf.Lerp( rect.yMin, rect.yMax, uv.y );bufTexCoords.Add( uv );}}public static void Push(float distance) {for(int i=0; i<bufVertices.Count; i++) {Vector3 normal = bufNormals[i];bufVertices[i] += normal * distance;}}public static Mesh CreateMesh() {if(bufIndices.Count == 0) {return null;}Mesh mesh = new Mesh();mesh.vertices = bufVertices.ToArray();mesh.normals = bufNormals.ToArray();mesh.uv = bufTexCoords.ToArray();mesh.uv2 = bufTexCoords.ToArray();mesh.triangles = bufIndices.ToArray();bufVertices.Clear();bufNormals.Clear();bufTexCoords.Clear();bufIndices.Clear();return mesh;}




溶解shader :

把这个shader 用于贴花的material,即可产生溶解贴花的效果

Properties{_MainTex("Base (RGB)", 2D) = "white" {}     _DissolveTex("DissolveTex (RGB)", 2D) = "white" {}_Tile("DissolveTile", Range(0.1, 1)) = 1_Amount("DissAmount", Range(0, 1)) = 0.5      // 声明一个用于控制溶解阈值的变量_DissSize("DissSize", Range(0, 1)) = 0.1_DissColor("DissColor", Color) = (1,0,0,1)_AddColor("AddColor", Color) = (1,1,0,1)}SubShader{Tags{ "RenderType" = "Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert  #pragma fragment frag  #pragma multi_compile_fog  #include "UnityCG.cginc"  sampler2D _MainTex,_DissolveTex;fixed4 _MainTex_ST,_DissolveTex_ST;half _Tile,_Amount,_DissSize;      //在这里定义half4 _DissColor,_AddColor;struct appdata_t {float4 vertex : POSITION;float2 texcoord : TEXCOORD0;};struct v2f {float4 vertex : SV_POSITION;half2 texcoord : TEXCOORD0;UNITY_FOG_COORDS(1)};v2f vert(appdata_t v){v2f o;o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);UNITY_TRANSFER_FOG(o,o.vertex);return o;}fixed4 frag(v2f i) : SV_Target{fixed4 col = tex2D(_MainTex, i.texcoord);float ClipTex = tex2D(_DissolveTex, i.texcoord / _Tile).r;   //read the R float ClipAmount = ClipTex - _Amount;       //和噪声纹理的值作比较if (_Amount > 0){if (ClipAmount < 0)    // clip the r less than zero {clip(-0.1);}else {if (ClipAmount < _DissSize){float4 finalColor = lerp(_DissColor,_AddColor,ClipAmount / _DissSize) * 2;col = col * finalColor;    // color blend }}}UNITY_APPLY_FOG(i.fogCoord, col);UNITY_OPAQUE_ALPHA(col.a);return col;}ENDCG}}}

贴花插件:

https://www.assetstore.unity3d.com/en/#!/content/13889

0 0
原创粉丝点击