359 lines
8.8 KiB
C#
359 lines
8.8 KiB
C#
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<int> affected = new List<int>();
|
|
|
|
private List<float> distances = new List<float>();
|
|
|
|
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<Collider>();
|
|
}
|
|
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;
|
|
}
|
|
}
|