Files
2026-02-21 16:45:37 +08:00

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;
}
}