400 lines
13 KiB
C#
400 lines
13 KiB
C#
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<SkinnedMeshRenderer>();
|
|
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<SkinnedMeshRenderer>();
|
|
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<SkinnedMeshRenderer>();
|
|
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<SkinnedMeshRenderer>();
|
|
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;
|
|
}
|
|
}
|