using System; using UnityEngine; [ExecuteInEditMode] public class MegaAttach : MonoBehaviour { [Serializable] public class MegaSkinVert { public float[] weights; public Transform[] bones; public Matrix4x4[] bindposes; public int vert; public MegaSkinVert() { weights = new float[4]; bones = new Transform[4]; bindposes = new Matrix4x4[4]; } } public MegaModifiers target; [HideInInspector] public Vector3 BaryCoord = Vector3.zero; [HideInInspector] public int[] BaryVerts = new int[3]; [HideInInspector] public bool attached; [HideInInspector] public Vector3 BaryCoord1 = Vector3.zero; [HideInInspector] public int[] BaryVerts1 = new int[3]; public Vector3 attachforward = Vector3.forward; public Vector3 AxisRot = Vector3.zero; public float radius = 0.1f; public Vector3 up = Vector3.up; public bool worldSpace; private Vector3 pt = Vector3.zero; private Vector3 norm = Vector3.zero; public bool skinned; public bool updateRotation = true; public MegaSkinVert[] skinverts; public Quaternion attachrot = Quaternion.identity; private Vector3[] calcskinverts; [ContextMenu("Help")] public void Help() { Application.OpenURL("http://www.west-racing.com/mf/?page_id=2645"); } public void DetachIt() { attached = false; } public void AttachIt() { if (!target) { return; } attached = true; if (!InitSkin()) { Mesh mesh = target.mesh; Vector3 vector = target.transform.InverseTransformPoint(pt); Vector3[] sverts = target.sverts; int[] triangles = mesh.triangles; int index = -1; MegaNearestPointTest.NearestPointOnMesh1(vector, sverts, triangles, ref index, ref BaryCoord); if (index >= 0) { BaryVerts[0] = triangles[index]; BaryVerts[1] = triangles[index + 1]; BaryVerts[2] = triangles[index + 2]; } MegaNearestPointTest.NearestPointOnMesh1(vector + attachforward, sverts, triangles, ref index, ref BaryCoord1); if (index >= 0) { BaryVerts1[0] = triangles[index]; BaryVerts1[1] = triangles[index + 1]; BaryVerts1[2] = triangles[index + 2]; } } } public void AttachIt(Vector3 pos) { pt = pos; AttachIt(); } private void OnDrawGizmosSelected() { pt = base.transform.position; Gizmos.color = Color.white; Gizmos.DrawSphere(pt, radius); if (!target || !target.mesh) { return; } if (attached) { SkinnedMeshRenderer component = target.GetComponent(); if ((bool)component) { Vector3 position = base.transform.position; Vector3 center = position; Gizmos.color = Color.green; Gizmos.DrawSphere(center, radius); } else { Vector3 coordMine = GetCoordMine(target.sverts[BaryVerts[0]], target.sverts[BaryVerts[1]], target.sverts[BaryVerts[2]], BaryCoord); Vector3 vector = target.transform.TransformPoint(coordMine); Gizmos.color = Color.green; Gizmos.DrawSphere(vector, radius); Vector3 vector2 = target.transform.TransformDirection(norm * 40f); Gizmos.DrawLine(vector, vector + vector2); } return; } SkinnedMeshRenderer component2 = target.GetComponent(); if ((bool)component2) { CalcSkinVerts(); Mesh mesh = target.mesh; Vector3 vector3 = pt; Vector3[] array = calcskinverts; int[] triangles = mesh.triangles; int index = -1; Vector3 bary = Vector3.zero; Vector3 position2 = MegaNearestPointTest.NearestPointOnMesh1(vector3, array, triangles, ref index, ref bary); Vector3 vector4 = target.transform.TransformPoint(position2); if (index >= 0) { Vector3 coordMine2 = GetCoordMine(array[triangles[index]], array[triangles[index + 1]], array[triangles[index + 2]], bary); vector4 = coordMine2; } Gizmos.color = Color.red; Gizmos.DrawSphere(vector4, radius); Gizmos.color = Color.blue; position2 = MegaNearestPointTest.NearestPointOnMesh1(vector3 + attachforward, array, triangles, ref index, ref bary); Vector3 vector5 = position2; Gizmos.DrawSphere(vector5, radius); Gizmos.color = Color.yellow; Gizmos.DrawLine(vector4, vector5); } else { Mesh mesh2 = target.mesh; Vector3 vector6 = target.transform.InverseTransformPoint(pt); Vector3[] sverts = target.sverts; int[] triangles2 = mesh2.triangles; int index2 = -1; Vector3 bary2 = Vector3.zero; Vector3 position3 = MegaNearestPointTest.NearestPointOnMesh1(vector6, sverts, triangles2, ref index2, ref bary2); Vector3 vector7 = target.transform.TransformPoint(position3); if (index2 >= 0) { Vector3 coordMine3 = GetCoordMine(sverts[triangles2[index2]], sverts[triangles2[index2 + 1]], sverts[triangles2[index2 + 2]], bary2); vector7 = target.transform.TransformPoint(coordMine3); } Gizmos.color = Color.red; Gizmos.DrawSphere(vector7, radius); Gizmos.color = Color.blue; position3 = MegaNearestPointTest.NearestPointOnMesh1(vector6 + attachforward, sverts, triangles2, ref index2, ref bary2); Vector3 vector8 = target.transform.TransformPoint(position3); Gizmos.DrawSphere(vector8, radius); Gizmos.color = Color.yellow; Gizmos.DrawLine(vector7, vector8); } } private void LateUpdate() { if (!attached) { return; } if (skinned) { GetSkinPos1(); } else if (worldSpace) { Vector3 vector = target.sverts[BaryVerts[0]]; Vector3 vector2 = target.sverts[BaryVerts[1]]; Vector3 vector3 = target.sverts[BaryVerts[2]]; Vector3 vector4 = target.transform.localToWorldMatrix.MultiplyPoint(GetCoordMine(vector, vector2, vector3, BaryCoord)); base.transform.position = vector4; if (updateRotation) { Vector3 lhs = vector2 - vector; Vector3 rhs = vector3 - vector2; norm = Vector3.Cross(lhs, rhs); vector = target.sverts[BaryVerts1[0]]; vector2 = target.sverts[BaryVerts1[1]]; vector3 = target.sverts[BaryVerts1[2]]; Vector3 vector5 = target.transform.localToWorldMatrix.MultiplyPoint(GetCoordMine(vector, vector2, vector3, BaryCoord1)) - vector4; Quaternion quaternion = Quaternion.Euler(AxisRot); if (vector5 != Vector3.zero) { Quaternion rotation = Quaternion.LookRotation(vector5, norm) * quaternion; base.transform.rotation = rotation; } } } else { Vector3 vector6 = target.sverts[BaryVerts[0]]; Vector3 vector7 = target.sverts[BaryVerts[1]]; Vector3 vector8 = target.sverts[BaryVerts[2]]; Vector3 coordMine = GetCoordMine(vector6, vector7, vector8, BaryCoord); base.transform.localPosition = coordMine; if (updateRotation) { Vector3 lhs2 = vector7 - vector6; Vector3 rhs2 = vector8 - vector7; norm = Vector3.Cross(lhs2, rhs2); vector6 = target.sverts[BaryVerts1[0]]; vector7 = target.sverts[BaryVerts1[1]]; vector8 = target.sverts[BaryVerts1[2]]; Vector3 forward = GetCoordMine(vector6, vector7, vector8, BaryCoord1) - coordMine; Quaternion quaternion2 = Quaternion.Euler(AxisRot); Quaternion localRotation = Quaternion.LookRotation(forward, norm) * quaternion2; base.transform.localRotation = localRotation; } } } private Vector3 GetCoordMine(Vector3 A, Vector3 B, Vector3 C, Vector3 bary) { Vector3 zero = Vector3.zero; zero.x = bary.x * A.x + bary.y * B.x + bary.z * C.x; zero.y = bary.x * A.y + bary.y * B.y + bary.z * C.y; zero.z = bary.x * A.z + bary.y * B.z + bary.z * C.z; return zero; } private bool InitSkin() { if ((bool)target) { SkinnedMeshRenderer component = target.GetComponent(); if ((bool)component) { Quaternion rotation = base.transform.rotation; attachrot = Quaternion.identity; skinned = true; Mesh sharedMesh = component.sharedMesh; Vector3 position = base.transform.position; CalcSkinVerts(); Vector3 vector = position; Vector3[] verts = calcskinverts; int[] triangles = sharedMesh.triangles; int index = -1; MegaNearestPointTest.NearestPointOnMesh1(vector, verts, triangles, ref index, ref BaryCoord); if (index >= 0) { BaryVerts[0] = triangles[index]; BaryVerts[1] = triangles[index + 1]; BaryVerts[2] = triangles[index + 2]; } MegaNearestPointTest.NearestPointOnMesh1(vector + attachforward, verts, triangles, ref index, ref BaryCoord1); if (index >= 0) { BaryVerts1[0] = triangles[index]; BaryVerts1[1] = triangles[index + 1]; BaryVerts1[2] = triangles[index + 2]; } skinverts = new MegaSkinVert[6]; for (int i = 0; i < 3; i++) { int num = BaryVerts[i]; BoneWeight boneWeight = sharedMesh.boneWeights[num]; skinverts[i] = new MegaSkinVert(); skinverts[i].vert = num; skinverts[i].weights[0] = boneWeight.weight0; skinverts[i].weights[1] = boneWeight.weight1; skinverts[i].weights[2] = boneWeight.weight2; skinverts[i].weights[3] = boneWeight.weight3; skinverts[i].bones[0] = component.bones[boneWeight.boneIndex0]; skinverts[i].bones[1] = component.bones[boneWeight.boneIndex1]; skinverts[i].bones[2] = component.bones[boneWeight.boneIndex2]; skinverts[i].bones[3] = component.bones[boneWeight.boneIndex3]; skinverts[i].bindposes[0] = sharedMesh.bindposes[boneWeight.boneIndex0]; skinverts[i].bindposes[1] = sharedMesh.bindposes[boneWeight.boneIndex1]; skinverts[i].bindposes[2] = sharedMesh.bindposes[boneWeight.boneIndex2]; skinverts[i].bindposes[3] = sharedMesh.bindposes[boneWeight.boneIndex3]; } for (int j = 3; j < 6; j++) { int num2 = BaryVerts1[j - 3]; BoneWeight boneWeight2 = sharedMesh.boneWeights[num2]; skinverts[j] = new MegaSkinVert(); skinverts[j].vert = num2; skinverts[j].weights[0] = boneWeight2.weight0; skinverts[j].weights[1] = boneWeight2.weight1; skinverts[j].weights[2] = boneWeight2.weight2; skinverts[j].weights[3] = boneWeight2.weight3; skinverts[j].bones[0] = component.bones[boneWeight2.boneIndex0]; skinverts[j].bones[1] = component.bones[boneWeight2.boneIndex1]; skinverts[j].bones[2] = component.bones[boneWeight2.boneIndex2]; skinverts[j].bones[3] = component.bones[boneWeight2.boneIndex3]; skinverts[j].bindposes[0] = sharedMesh.bindposes[boneWeight2.boneIndex0]; skinverts[j].bindposes[1] = sharedMesh.bindposes[boneWeight2.boneIndex1]; skinverts[j].bindposes[2] = sharedMesh.bindposes[boneWeight2.boneIndex2]; skinverts[j].bindposes[3] = sharedMesh.bindposes[boneWeight2.boneIndex3]; } GetSkinPos1(); attachrot = Quaternion.Inverse(base.transform.rotation) * rotation; return true; } skinned = false; } return false; } private Vector3 GetSkinPos(int i) { Vector3 point = target.sverts[skinverts[i].vert]; Vector3 position = skinverts[i].bindposes[0].MultiplyPoint(point); Vector3 vector = skinverts[i].bones[0].TransformPoint(position) * skinverts[i].weights[0]; position = skinverts[i].bindposes[1].MultiplyPoint(point); vector += skinverts[i].bones[1].TransformPoint(position) * skinverts[i].weights[1]; position = skinverts[i].bindposes[2].MultiplyPoint(point); vector += skinverts[i].bones[2].TransformPoint(position) * skinverts[i].weights[2]; position = skinverts[i].bindposes[3].MultiplyPoint(point); return vector + skinverts[i].bones[3].TransformPoint(position) * skinverts[i].weights[3]; } private void CalcSkinVerts() { if (calcskinverts == null || calcskinverts.Length != target.sverts.Length) { calcskinverts = new Vector3[target.sverts.Length]; } SkinnedMeshRenderer component = target.GetComponent(); Mesh mesh = target.mesh; Matrix4x4[] bindposes = mesh.bindposes; BoneWeight[] boneWeights = mesh.boneWeights; for (int i = 0; i < target.sverts.Length; i++) { Vector3 zero = Vector3.zero; Vector3 point = target.sverts[i]; Vector3 position = bindposes[boneWeights[i].boneIndex0].MultiplyPoint(point); zero += component.bones[boneWeights[i].boneIndex0].TransformPoint(position) * boneWeights[i].weight0; position = bindposes[boneWeights[i].boneIndex1].MultiplyPoint(point); zero += component.bones[boneWeights[i].boneIndex1].TransformPoint(position) * boneWeights[i].weight1; position = bindposes[boneWeights[i].boneIndex2].MultiplyPoint(point); zero += component.bones[boneWeights[i].boneIndex2].TransformPoint(position) * boneWeights[i].weight2; position = bindposes[boneWeights[i].boneIndex3].MultiplyPoint(point); zero += component.bones[boneWeights[i].boneIndex3].TransformPoint(position) * boneWeights[i].weight3; calcskinverts[i] = zero; } } private void GetSkinPos1() { Vector3 skinPos = GetSkinPos(0); Vector3 skinPos2 = GetSkinPos(1); Vector3 skinPos3 = GetSkinPos(2); Vector3 coordMine = GetCoordMine(skinPos, skinPos2, skinPos3, BaryCoord); base.transform.position = coordMine; Vector3 lhs = skinPos2 - skinPos; Vector3 rhs = skinPos3 - skinPos2; norm = Vector3.Cross(lhs, rhs); skinPos = GetSkinPos(3); skinPos2 = GetSkinPos(4); skinPos3 = GetSkinPos(5); Vector3 forward = GetCoordMine(skinPos, skinPos2, skinPos3, BaryCoord1) - coordMine; Quaternion quaternion = Quaternion.Euler(AxisRot); Quaternion rotation = Quaternion.LookRotation(forward, norm) * quaternion * attachrot; base.transform.rotation = rotation; } }