using System.Collections.Generic; using UnityEngine; [AddComponentMenu("Modifiers/Collision Deform")] public class MegaCollisionDeform : MegaModifier { public GameObject obj; public float decay = 1f; public bool usedecay; public Vector3 normal = Vector3.up; private List affected = new List(); private List distances = new List(); private Matrix4x4 mat = default(Matrix4x4); private Vector3[] offsets; private Vector3[] normals; public MegaColliderMesh colmesh; public MegaDeformType method = MegaDeformType.NearPoint; public float distance; public float bulgeExtendValue; public float bulgeValue; public bool bulge; public AnimationCurve bulgeCrv = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(1f, 1f)); private float[] vertdist; private Vector3[] vertoffsets; private Vector3[] nearest; private Vector3[] vels; public float btime = 1f; public float retspd = 1f; private Collider col; private float[] penetration; public GameObject hitObject; private const float EPSILON = 1E-06f; public override string ModName() { return "Deform"; } public override string GetHelpURL() { return "Deform.htm"; } private void DeformMeshMine() { if (col == null) { return; } for (int i = 0; i < verts.Length; i++) { Vector3 position = verts[i] + offsets[i]; Vector3 vector = base.transform.TransformPoint(position); if (col.bounds.Contains(vector)) { Ray ray = new Ray(vector, normals[i]); RaycastHit hitInfo; if (col.Raycast(ray, out hitInfo, 10f) && hitInfo.distance < 10f) { penetration[i] = hitInfo.distance; offsets[i] = -(normals[i] * (hitInfo.distance + 0.01f)); } } } if (!usedecay) { for (int j = 0; j < verts.Length; j++) { sverts[j].x = verts[j].x + offsets[j].x; sverts[j].y = verts[j].y + offsets[j].y; sverts[j].z = verts[j].z + offsets[j].z; } return; } for (int k = 0; k < verts.Length; k++) { offsets[k].x *= decay; offsets[k].y *= decay; offsets[k].z *= decay; sverts[k].x = verts[k].x + offsets[k].x; sverts[k].y = verts[k].y + offsets[k].y; sverts[k].z = verts[k].z + offsets[k].z; } } private void DeformMesh() { float num = distance * 0.001f; int index = -1; Vector3 bary = Vector3.zero; bool flag = false; for (int i = 0; i < verts.Length; i++) { Vector3 vector = verts[i]; Vector3 point = base.transform.TransformPoint(vector + normals[i] * num); if (col.bounds.Contains(point)) { Vector3 vector2 = col.transform.worldToLocalMatrix.MultiplyPoint(point); Vector3 vector3 = MegaNearestPointTest.NearestPointOnMesh1(vector2, colmesh.verts, colmesh.tris, ref index, ref bary); Vector3 rhs = vector2 - vector3; Vector3 lhs = FaceNormal(colmesh.verts, colmesh.tris, index); if (Vector3.Dot(lhs, rhs) < 0f) { vector3 = col.transform.localToWorldMatrix.MultiplyPoint(vector3); sverts[i] = base.transform.worldToLocalMatrix.MultiplyPoint(vector3); sverts[i] -= normals[i] * num; flag = true; } else { sverts[i] = verts[i]; } } else { sverts[i] = verts[i]; } } if (flag && bulge) { for (int j = 0; j < verts.Length; j++) { Vector3 vector4 = verts[j]; Vector3 point2 = base.transform.TransformPoint(vector4 + normals[j] * num); Vector3 vector5 = col.transform.worldToLocalMatrix.MultiplyPoint(point2); Vector3 b = MegaNearestPointTest.NearestPointOnMesh1(vector5, colmesh.verts, colmesh.tris, ref index, ref bary); float num2 = Vector3.Distance(vector5, b); float time = num2 / (bulgeExtendValue + 1E-05f); float num3 = bulgeCrv.Evaluate(time); float num4 = num3 * bulgeValue; sverts[j].x = sverts[j].x + normals[j].x * num4; sverts[j].y = sverts[j].y + normals[j].y * num4; sverts[j].z = sverts[j].z + normals[j].z * num4; } } } [ContextMenu("Reset Offsets")] public void ResetOffsets() { vertdist = null; } private void DeformMeshNew() { if (vertdist == null || vertdist.Length != verts.Length) { vertdist = new float[verts.Length]; vertoffsets = new Vector3[verts.Length]; nearest = new Vector3[verts.Length]; vels = new Vector3[verts.Length]; } float num = distance * 0.001f; int index = -1; Vector3 bary = Vector3.zero; float num2 = 0f; int num3 = 0; for (int i = 0; i < verts.Length; i++) { Vector3 vector = verts[i]; Vector3 point = base.transform.TransformPoint(vector + normals[i] * num); if (col.bounds.Contains(point)) { Vector3 vector2 = col.transform.worldToLocalMatrix.MultiplyPoint(point); Vector3 vector3 = MegaNearestPointTest.NearestPointOnMesh1(vector2, colmesh.verts, colmesh.tris, ref index, ref bary); Vector3 rhs = vector2 - vector3; float num4 = Vector3.Distance(vector2, vector3); Vector3 lhs = FaceNormal(colmesh.verts, colmesh.tris, index); if (Vector3.Dot(lhs, rhs) < 0f) { num2 += num4; num4 = 0f - num4; } vector3 = col.transform.localToWorldMatrix.MultiplyPoint(vector3); nearest[i] = base.transform.worldToLocalMatrix.MultiplyPoint(vector3); vertdist[i] = num4; } else { Vector3 vector4 = col.transform.worldToLocalMatrix.MultiplyPoint(point); Vector3 vector5 = MegaNearestPointTest.NearestPointOnMesh1(vector4, colmesh.verts, colmesh.tris, ref index, ref bary); float num5 = Vector3.Distance(vector4, vector5); vertdist[i] = num5; vector5 = col.transform.localToWorldMatrix.MultiplyPoint(vector5); nearest[i] = base.transform.worldToLocalMatrix.MultiplyPoint(vector5); num3++; } } if (num2 == 0f) { for (int j = 0; j < verts.Length; j++) { sverts[j] = verts[j] + vertoffsets[j]; vertoffsets[j] *= retspd; } return; } for (int k = 0; k < verts.Length; k++) { if (vertdist[k] < 0f) { vertoffsets[k] = nearest[k] - verts[k]; } else { Vector3 target = normals[k] * (num2 / (float)num3 * bulgeValue); vertoffsets[k] = Vector3.SmoothDamp(vertoffsets[k], target, ref vels[k], btime); } sverts[k] = verts[k] + vertoffsets[k]; vertoffsets[k] *= retspd; } } private Vector3 FaceNormal(Vector3[] verts, int[] tris, int f) { Vector3 result = verts[tris[f]]; Vector3 vector = verts[tris[f + 1]]; Vector3 vector2 = verts[tris[f + 2]]; float num = vector.x - result.x; float num2 = vector.y - result.y; float num3 = vector.z - result.z; float num4 = vector2.x - vector.x; float num5 = vector2.y - vector.y; float num6 = vector2.z - vector.z; result.x = num2 * num6 - num3 * num5; result.y = num3 * num4 - num * num6; result.z = num * num5 - num2 * num4; return result; } public override void Modify(MegaModifiers mc) { switch (method) { case MegaDeformType.Old: DeformMesh(); break; case MegaDeformType.RayCast: DeformMeshMine(); break; case MegaDeformType.NearPoint: DeformMeshNew(); break; } } public override bool ModLateUpdate(MegaModContext mc) { return Prepare(mc); } public override bool Prepare(MegaModContext mc) { if (colmesh == null) { colmesh = new MegaColliderMesh(); } if (colmesh.obj != hitObject && hitObject != null) { colmesh = new MegaColliderMesh(); colmesh.mesh = MegaUtils.GetMesh(hitObject); colmesh.verts = colmesh.mesh.vertices; colmesh.tris = colmesh.mesh.triangles; colmesh.normals = colmesh.mesh.normals; colmesh.obj = hitObject; } if ((bool)hitObject) { col = hitObject.GetComponent(); } if (hitObject == null) { return false; } affected.Clear(); distances.Clear(); if (offsets == null || offsets.Length != mc.mod.verts.Length) { offsets = new Vector3[mc.mod.verts.Length]; } if (normals == null || normals.Length != verts.Length) { normals = mc.mod.mesh.normals; } if (penetration == null || penetration.Length != mc.mod.verts.Length) { penetration = new float[mc.mod.verts.Length]; } mat = Matrix4x4.identity; SetAxis(mat); return true; } public override void PrepareMT(MegaModifiers mc, int cores) { } public override void DoWork(MegaModifiers mc, int index, int start, int end, int cores) { if (index == 0) { Modify(mc); } } private int intersect_triangle(Vector3 orig, Vector3 dir, Vector3 vert0, Vector3 vert1, Vector3 vert2, out float t, out float u, out float v) { Vector3 vector = vert1 - vert0; Vector3 vector2 = vert2 - vert0; Vector3 rhs = Vector3.Cross(dir, vector2); float num = Vector3.Dot(vector, rhs); t = (u = (v = 0f)); if (num > -1E-06f && num < 1E-06f) { return 0; } float num2 = 1f / num; Vector3 lhs = orig - vert0; u = Vector3.Dot(lhs, rhs) * num2; if (u < 0f || u > 1f) { return 0; } Vector3 rhs2 = Vector3.Cross(lhs, vector); v = Vector3.Dot(dir, rhs2) * num2; if (v < 0f || u + v > 1f) { return 0; } t = Vector3.Dot(vector2, rhs2) * num2; return 1; } }