using System.Collections.Generic; using UnityEngine; [ExecuteInEditMode] public class MegaWrap : MonoBehaviour { public float gap; public float shrink = 1f; public List neededVerts = new List(); public Vector3[] skinnedVerts; public Mesh mesh; public Vector3 offset = Vector3.zero; public bool targetIsSkin; public bool sourceIsSkin; public int nomapcount; public Matrix4x4[] bindposes; public BoneWeight[] boneweights; public Transform[] bones; public float size = 0.01f; public int vertindex; public Vector3[] freeverts; public Vector3[] startverts; public Vector3[] verts; public MegaBindVert[] bindverts; public MegaModifyObject target; public float maxdist = 0.25f; public int maxpoints = 4; public bool WrapEnabled = true; public MegaNormalMethod NormalMethod; private Vector3 e11 = Vector3.zero; private Vector3 e22 = Vector3.zero; private Vector3 cr = Vector3.zero; private Vector3 gcp = Vector3.zero; private SkinnedMeshRenderer tmesh; public MegaNormMap[] mapping; public int[] tris; public Vector3[] facenorms; public Vector3[] norms; [ContextMenu("Help")] public void Help() { Application.OpenURL("http://www.west-racing.com/mf/?page_id=3709"); } private Vector4 Plane(Vector3 v1, Vector3 v2, Vector3 v3) { Vector3 vector = Vector4.zero; vector.x = (v2.y - v1.y) * (v3.z - v1.z) - (v2.z - v1.z) * (v3.y - v1.y); vector.y = (v2.z - v1.z) * (v3.x - v1.x) - (v2.x - v1.x) * (v3.z - v1.z); vector.z = (v2.x - v1.x) * (v3.y - v1.y) - (v2.y - v1.y) * (v3.x - v1.x); vector = vector.normalized; return new Vector4(vector.x, vector.y, vector.z, 0f - Vector3.Dot(v2, vector)); } private float PlaneDist(Vector3 p, Vector4 plane) { Vector3 lhs = plane; return Vector3.Dot(lhs, p) + plane.w; } public float GetDistance(Vector3 p, Vector3 p0, Vector3 p1, Vector3 p2) { return MegaNearestPointTest.DistPoint3Triangle3Dbl(p, p0, p1, p2); } public float GetPlaneDistance(Vector3 p, Vector3 p0, Vector3 p1, Vector3 p2) { Vector4 plane = Plane(p0, p1, p2); return PlaneDist(p, plane); } public Vector3 MyBary(Vector3 p, Vector3 p0, Vector3 p1, Vector3 p2) { Vector3 zero = Vector3.zero; Vector3 lhs = FaceNormal(p0, p1, p2); float num = Vector3.Dot(lhs, Vector3.Cross(p1 - p0, p2 - p0)); float num2 = Vector3.Dot(lhs, Vector3.Cross(p1 - p, p2 - p)); float num3 = Vector3.Dot(lhs, Vector3.Cross(p2 - p, p0 - p)); zero.x = num2 / num; zero.y = num3 / num; zero.z = 1f - zero.x - zero.y; return zero; } public Vector3 MyBary1(Vector3 p, Vector3 a, Vector3 b, Vector3 c) { Vector3 vector = b - a; Vector3 vector2 = c - a; Vector3 lhs = p - a; float num = Vector3.Dot(vector, vector); float num2 = Vector3.Dot(vector, vector2); float num3 = Vector3.Dot(vector2, vector2); float num4 = Vector3.Dot(lhs, vector); float num5 = Vector3.Dot(lhs, vector2); float num6 = num * num3 - num2 * num2; float num7 = (num3 * num4 - num2 * num5) / num6; float num8 = (num * num5 - num2 * num4) / num6; float x = 1f - num8 - num7; return new Vector3(x, num8, num7); } public Vector3 CalcBary(Vector3 p, Vector3 p0, Vector3 p1, Vector3 p2) { return MyBary(p, p0, p1, p2); } public float CalcArea(Vector3 p0, Vector3 p1, Vector3 p2) { Vector3 lhs = p1 - p0; Vector3 rhs = p2 - p0; return 0.5f * Vector3.Cross(lhs, rhs).magnitude; } public Vector3 FaceNormal(Vector3 p0, Vector3 p1, Vector3 p2) { e11.x = p1.x - p0.x; e11.y = p1.y - p0.y; e11.z = p1.z - p0.z; e22.x = p2.x - p0.x; e22.y = p2.y - p0.y; e22.z = p2.z - p0.z; cr.x = e11.y * e22.z - e22.y * e11.z; cr.y = 0f - (e11.x * e22.z - e22.x * e11.z); cr.z = e11.x * e22.y - e22.x * e11.y; return cr; } private static void CopyBlendShapes(Mesh mesh1, Mesh clonemesh) { } public Mesh CloneMesh(Mesh m) { Mesh mesh = new Mesh(); mesh.vertices = m.vertices; mesh.uv2 = m.uv2; mesh.uv2 = m.uv2; mesh.uv = m.uv; mesh.normals = m.normals; mesh.tangents = m.tangents; mesh.colors = m.colors; mesh.subMeshCount = m.subMeshCount; for (int i = 0; i < m.subMeshCount; i++) { mesh.SetTriangles(m.GetTriangles(i), i); } CopyBlendShapes(m, mesh); mesh.boneWeights = m.boneWeights; mesh.bindposes = m.bindposes; mesh.name = m.name; mesh.RecalculateBounds(); return mesh; } [ContextMenu("Reset Mesh")] public void ResetMesh() { if ((bool)mesh) { mesh.vertices = startverts; mesh.RecalculateBounds(); RecalcNormals(); } target = null; bindverts = null; } public void SetMesh() { MeshFilter component = GetComponent(); Mesh mesh = null; if (component != null) { mesh = component.sharedMesh; } else { SkinnedMeshRenderer skinnedMeshRenderer = (SkinnedMeshRenderer)GetComponent(typeof(SkinnedMeshRenderer)); if (skinnedMeshRenderer != null) { mesh = skinnedMeshRenderer.sharedMesh; } } if (mesh != null) { this.mesh = CloneMesh(mesh); if ((bool)component) { component.sharedMesh = this.mesh; return; } SkinnedMeshRenderer skinnedMeshRenderer2 = (SkinnedMeshRenderer)GetComponent(typeof(SkinnedMeshRenderer)); skinnedMeshRenderer2.sharedMesh = this.mesh; } } public void Attach(MegaModifyObject modobj) { targetIsSkin = false; sourceIsSkin = false; if ((bool)this.mesh && startverts != null) { this.mesh.vertices = startverts; } if (modobj == null) { bindverts = null; return; } nomapcount = 0; if ((bool)this.mesh) { this.mesh.vertices = startverts; } MeshFilter component = GetComponent(); Mesh mesh = null; if (component != null) { mesh = component.mesh; } else { SkinnedMeshRenderer skinnedMeshRenderer = (SkinnedMeshRenderer)GetComponent(typeof(SkinnedMeshRenderer)); if (skinnedMeshRenderer != null) { mesh = skinnedMeshRenderer.sharedMesh; sourceIsSkin = true; } } if (mesh == null) { Debug.LogWarning("No Mesh found on the target object, make sure target has a mesh and MegaFiers modifier attached!"); return; } if (this.mesh == null) { this.mesh = CloneMesh(mesh); } if ((bool)component) { component.mesh = this.mesh; } else { SkinnedMeshRenderer skinnedMeshRenderer2 = (SkinnedMeshRenderer)GetComponent(typeof(SkinnedMeshRenderer)); skinnedMeshRenderer2.sharedMesh = this.mesh; } if (!sourceIsSkin) { SkinnedMeshRenderer skinnedMeshRenderer3 = (SkinnedMeshRenderer)modobj.GetComponent(typeof(SkinnedMeshRenderer)); if (skinnedMeshRenderer3 != null) { targetIsSkin = true; if (!sourceIsSkin) { Mesh sharedMesh = skinnedMeshRenderer3.sharedMesh; bindposes = sharedMesh.bindposes; boneweights = sharedMesh.boneWeights; bones = skinnedMeshRenderer3.bones; skinnedVerts = sharedMesh.vertices; } } } if (targetIsSkin && (boneweights == null || boneweights.Length == 0)) { targetIsSkin = false; } neededVerts.Clear(); verts = this.mesh.vertices; startverts = this.mesh.vertices; freeverts = new Vector3[startverts.Length]; Vector3[] array = modobj.verts; int[] array2 = modobj.tris; bindverts = new MegaBindVert[verts.Length]; Matrix4x4 matrix4x = base.transform.localToWorldMatrix * modobj.transform.worldToLocalMatrix; List list = new List(); Vector3 zero = Vector3.zero; Vector3 zero2 = Vector3.zero; Vector3 zero3 = Vector3.zero; for (int i = 0; i < verts.Length; i++) { MegaBindVert megaBindVert = new MegaBindVert(); bindverts[i] = megaBindVert; Vector3 vector = matrix4x.MultiplyPoint(verts[i]); vector = base.transform.TransformPoint(verts[i]); vector = modobj.transform.InverseTransformPoint(vector); freeverts[i] = vector; list.Clear(); for (int j = 0; j < array2.Length; j += 3) { if (targetIsSkin && !sourceIsSkin) { zero = modobj.transform.InverseTransformPoint(GetSkinPos(array2[j])); zero2 = modobj.transform.InverseTransformPoint(GetSkinPos(array2[j + 1])); zero3 = modobj.transform.InverseTransformPoint(GetSkinPos(array2[j + 2])); } else { zero = array[array2[j]]; zero2 = array[array2[j + 1]]; zero3 = array[array2[j + 2]]; } float distance = GetDistance(vector, zero, zero2, zero3); if (!(Mathf.Abs(distance) < maxdist)) { continue; } MegaCloseFace item = new MegaCloseFace { dist = Mathf.Abs(distance), face = j }; bool flag = false; for (int k = 0; k < list.Count; k++) { if (item.dist < list[k].dist) { list.Insert(k, item); flag = true; break; } } if (!flag) { list.Add(item); } } float num = 0f; int count = maxpoints; if (count == 0) { count = list.Count; } for (int l = 0; l < count; l++) { if (l < list.Count) { int face = list[l].face; if (targetIsSkin && !sourceIsSkin) { zero = modobj.transform.InverseTransformPoint(GetSkinPos(array2[face])); zero2 = modobj.transform.InverseTransformPoint(GetSkinPos(array2[face + 1])); zero3 = modobj.transform.InverseTransformPoint(GetSkinPos(array2[face + 2])); } else { zero = array[array2[face]]; zero2 = array[array2[face + 1]]; zero3 = array[array2[face + 2]]; } Vector3 vector2 = FaceNormal(zero, zero2, zero3); float dist = list[l].dist; MegaBindInf megaBindInf = new MegaBindInf(); megaBindInf.dist = GetPlaneDistance(vector, zero, zero2, zero3); megaBindInf.face = face; megaBindInf.i0 = array2[face]; megaBindInf.i1 = array2[face + 1]; megaBindInf.i2 = array2[face + 2]; megaBindInf.bary = CalcBary(vector, zero, zero2, zero3); megaBindInf.weight = 1f / (1f + dist); megaBindInf.area = vector2.magnitude * 0.5f; num += megaBindInf.weight; megaBindVert.verts.Add(megaBindInf); } } if (maxpoints > 0 && maxpoints < megaBindVert.verts.Count) { megaBindVert.verts.RemoveRange(maxpoints, megaBindVert.verts.Count - maxpoints); } if (!sourceIsSkin && targetIsSkin) { for (int m = 0; m < megaBindVert.verts.Count; m++) { if (!neededVerts.Contains(megaBindVert.verts[m].i0)) { neededVerts.Add(megaBindVert.verts[m].i0); } if (!neededVerts.Contains(megaBindVert.verts[m].i1)) { neededVerts.Add(megaBindVert.verts[m].i1); } if (!neededVerts.Contains(megaBindVert.verts[m].i2)) { neededVerts.Add(megaBindVert.verts[m].i2); } } } if (num == 0f) { nomapcount++; } megaBindVert.weight = num; } } private void LateUpdate() { DoUpdate(); } public Vector3 GetSkinPos(int i) { Vector3 point = target.sverts[i]; Vector3 position = bindposes[boneweights[i].boneIndex0].MultiplyPoint(point); Vector3 vector = bones[boneweights[i].boneIndex0].TransformPoint(position) * boneweights[i].weight0; position = bindposes[boneweights[i].boneIndex1].MultiplyPoint(point); vector += bones[boneweights[i].boneIndex1].TransformPoint(position) * boneweights[i].weight1; position = bindposes[boneweights[i].boneIndex2].MultiplyPoint(point); vector += bones[boneweights[i].boneIndex2].TransformPoint(position) * boneweights[i].weight2; position = bindposes[boneweights[i].boneIndex3].MultiplyPoint(point); return vector + bones[boneweights[i].boneIndex3].TransformPoint(position) * boneweights[i].weight3; } public Vector3 GetCoordMine(Vector3 A, Vector3 B, Vector3 C, Vector3 bary) { gcp.x = bary.x * A.x + bary.y * B.x + bary.z * C.x; gcp.y = bary.x * A.y + bary.y * B.y + bary.z * C.y; gcp.z = bary.x * A.z + bary.y * B.z + bary.z * C.z; return gcp; } private void DoUpdate() { if (!WrapEnabled || target == null || bindverts == null) { return; } if (mesh == null) { SetMesh(); } if (mesh == null) { return; } if (targetIsSkin && neededVerts != null && neededVerts.Count > 0) { if (boneweights == null || tmesh == null) { tmesh = (SkinnedMeshRenderer)target.GetComponent(typeof(SkinnedMeshRenderer)); if (tmesh != null && !sourceIsSkin) { Mesh sharedMesh = tmesh.sharedMesh; bindposes = sharedMesh.bindposes; bones = tmesh.bones; boneweights = sharedMesh.boneWeights; } } for (int i = 0; i < neededVerts.Count; i++) { skinnedVerts[neededVerts[i]] = GetSkinPos(neededVerts[i]); } } Matrix4x4 identity = Matrix4x4.identity; Vector3 zero = Vector3.zero; if (targetIsSkin && !sourceIsSkin) { identity = base.transform.worldToLocalMatrix; for (int j = 0; j < bindverts.Length; j++) { if (bindverts[j].verts.Count <= 0) { continue; } zero = Vector3.zero; float num = 1f / bindverts[j].weight; int count = bindverts[j].verts.Count; for (int k = 0; k < count; k++) { MegaBindInf megaBindInf = bindverts[j].verts[k]; Vector3 vector = skinnedVerts[megaBindInf.i0]; Vector3 vector2 = skinnedVerts[megaBindInf.i1]; Vector3 vector3 = skinnedVerts[megaBindInf.i2]; Vector3 coordMine = GetCoordMine(vector, vector2, vector3, megaBindInf.bary); Vector3 vector4 = FaceNormal(vector, vector2, vector3); float num2 = 1f / Mathf.Sqrt(vector4.x * vector4.x + vector4.y * vector4.y + vector4.z * vector4.z); float num3 = megaBindInf.dist * shrink + gap; coordMine.x += num3 * vector4.x * num2; coordMine.y += num3 * vector4.y * num2; coordMine.z += num3 * vector4.z * num2; float num4 = megaBindInf.weight * num; if (k == 0) { zero.x = coordMine.x * num4; zero.y = coordMine.y * num4; zero.z = coordMine.z * num4; } else { zero.x += coordMine.x * num4; zero.y += coordMine.y * num4; zero.z += coordMine.z * num4; } } Vector3 vector5 = identity.MultiplyPoint3x4(zero); verts[j].x = vector5.x + offset.x; verts[j].y = vector5.y + offset.y; verts[j].z = vector5.z + offset.z; } } else { identity = base.transform.worldToLocalMatrix * target.transform.localToWorldMatrix; for (int l = 0; l < bindverts.Length; l++) { if (bindverts[l].verts.Count > 0) { zero = Vector3.zero; float num5 = 1f / bindverts[l].weight; for (int m = 0; m < bindverts[l].verts.Count; m++) { MegaBindInf megaBindInf2 = bindverts[l].verts[m]; Vector3 vector6 = target.sverts[megaBindInf2.i0]; Vector3 vector7 = target.sverts[megaBindInf2.i1]; Vector3 vector8 = target.sverts[megaBindInf2.i2]; Vector3 coordMine2 = GetCoordMine(vector6, vector7, vector8, megaBindInf2.bary); Vector3 vector9 = FaceNormal(vector6, vector7, vector8); float num6 = 1f / Mathf.Sqrt(vector9.x * vector9.x + vector9.y * vector9.y + vector9.z * vector9.z); float num7 = megaBindInf2.dist * shrink + gap; coordMine2.x += num7 * vector9.x * num6; coordMine2.y += num7 * vector9.y * num6; coordMine2.z += num7 * vector9.z * num6; float num8 = megaBindInf2.weight * num5; if (m == 0) { zero.x = coordMine2.x * num8; zero.y = coordMine2.y * num8; zero.z = coordMine2.z * num8; } else { zero.x += coordMine2.x * num8; zero.y += coordMine2.y * num8; zero.z += coordMine2.z * num8; } } } else { zero = freeverts[l]; } Vector3 vector10 = identity.MultiplyPoint3x4(zero); verts[l].x = vector10.x + offset.x; verts[l].y = vector10.y + offset.y; verts[l].z = vector10.z + offset.z; } } mesh.vertices = verts; RecalcNormals(); mesh.RecalculateBounds(); } private int[] FindFacesUsing(Vector3 p, Vector3 n) { List list = new List(); Vector3 zero = Vector3.zero; for (int i = 0; i < tris.Length; i += 3) { zero = verts[tris[i]]; if (zero.x == p.x && zero.y == p.y && zero.z == p.z) { if (n.Equals(norms[tris[i]])) { list.Add(i / 3); } continue; } zero = verts[tris[i + 1]]; if (zero.x == p.x && zero.y == p.y && zero.z == p.z) { if (n.Equals(norms[tris[i + 1]])) { list.Add(i / 3); } continue; } zero = verts[tris[i + 2]]; if (zero.x == p.x && zero.y == p.y && zero.z == p.z && n.Equals(norms[tris[i + 2]])) { list.Add(i / 3); } } return list.ToArray(); } public void BuildNormalMapping(Mesh mesh, bool force) { if (mapping == null || mapping.Length == 0 || force) { tris = mesh.triangles; norms = mesh.normals; facenorms = new Vector3[tris.Length / 3]; mapping = new MegaNormMap[verts.Length]; for (int i = 0; i < verts.Length; i++) { mapping[i] = new MegaNormMap(); mapping[i].faces = FindFacesUsing(verts[i], norms[i]); } } } public void RecalcNormals() { if (NormalMethod == MegaNormalMethod.Unity) { mesh.RecalculateNormals(); return; } if (mapping == null) { BuildNormalMapping(mesh, false); } RecalcNormals(mesh, verts); } public void RecalcNormals(Mesh ms, Vector3[] _verts) { int num = 0; Vector3 zero = Vector3.zero; Vector3 zero2 = Vector3.zero; Vector3 zero3 = Vector3.zero; Vector3 zero4 = Vector3.zero; Vector3 zero5 = Vector3.zero; for (int i = 0; i < tris.Length; i += 3) { zero = _verts[tris[i]]; zero2 = _verts[tris[i + 1]]; zero3 = _verts[tris[i + 2]]; zero4.x = zero2.x - zero.x; zero4.y = zero2.y - zero.y; zero4.z = zero2.z - zero.z; zero5.x = zero3.x - zero2.x; zero5.y = zero3.y - zero2.y; zero5.z = zero3.z - zero2.z; zero.x = zero4.y * zero5.z - zero4.z * zero5.y; zero.y = zero4.z * zero5.x - zero4.x * zero5.z; zero.z = zero4.x * zero5.y - zero4.y * zero5.x; facenorms[num++] = zero; } for (int j = 0; j < norms.Length; j++) { if (mapping[j].faces.Length > 0) { Vector3 vector = facenorms[mapping[j].faces[0]]; for (int k = 1; k < mapping[j].faces.Length; k++) { zero = facenorms[mapping[j].faces[k]]; vector.x += zero.x; vector.y += zero.y; vector.z += zero.z; } float f = vector.x * vector.x + vector.y * vector.y + vector.z * vector.z; f = 1f / Mathf.Sqrt(f); vector.x *= f; vector.y *= f; vector.z *= f; norms[j] = vector; } else { norms[j] = Vector3.up; } } ms.normals = norms; } }