using System; using System.Collections.Generic; using UnityEngine; namespace FIMSpace.FTail { [Serializable] public class FTail_SkinningVertexData { public Vector3 position; public int[] bonesIndexes; public int allMeshBonesCount; public float[] weights; public float[] debugDists; public float[] debugDistWeights; public float[] debugWeights; public FTail_SkinningVertexData(Vector3 pos) { position = pos; } public float DistanceToLine(Vector3 pos, Vector3 lineStart, Vector3 lineEnd) { Vector3 rhs = pos - lineStart; Vector3 normalized = (lineEnd - lineStart).normalized; float num = Vector3.Distance(lineStart, lineEnd); float num2 = Vector3.Dot(normalized, rhs); if (num2 <= 0f) { return Vector3.Distance(pos, lineStart); } if (num2 >= num) { return Vector3.Distance(pos, lineEnd); } Vector3 vector = normalized * num2; Vector3 b = lineStart + vector; return Vector3.Distance(pos, b); } public void CalculateVertexParameters(Vector3[] bonesPos, Quaternion[] bonesRot, Vector3[] boneAreas, int maxWeightedBones, float spread, Vector3 spreadOffset, float spreadPower = 1f) { allMeshBonesCount = bonesPos.Length; List list = new List(); for (int i = 0; i < bonesPos.Length; i++) { Vector3 lineEnd = ((i == bonesPos.Length - 1) ? Vector3.Lerp(bonesPos[i], bonesPos[i] + (bonesPos[i] - bonesPos[i - 1]), 0.9f) : Vector3.Lerp(bonesPos[i], bonesPos[i + 1], 0.9f)); lineEnd += bonesRot[i] * spreadOffset; float y = DistanceToLine(position, bonesPos[i], lineEnd); list.Add(new Vector2(i, y)); } list.Sort((Vector2 a, Vector2 b) => a.y.CompareTo(b.y)); int num = Mathf.Min(maxWeightedBones, bonesPos.Length); bonesIndexes = new int[num]; float[] array = new float[num]; for (int num2 = 0; num2 < num; num2++) { bonesIndexes[num2] = (int)list[num2].x; array[num2] = list[num2].y; } float[] array2 = new float[num]; AutoSetBoneWeights(array2, array, spread, spreadPower, boneAreas); float num3 = 1f; weights = new float[num]; for (int num4 = 0; num4 < num && (spread != 0f || num4 <= 0); num4++) { if (num3 <= 0f) { weights[num4] = 0f; continue; } float num5 = array2[num4]; num3 -= num5; if (num3 <= 0f) { num5 += num3; } else if (num4 == num - 1) { num5 += num3; } weights[num4] = num5; } } public void AutoSetBoneWeights(float[] weightForBone, float[] distToBone, float spread, float spreadPower, Vector3[] boneAreas) { int num = weightForBone.Length; float[] array = new float[num]; for (int i = 0; i < array.Length; i++) { array[i] = boneAreas[i].magnitude; } float[] array2 = new float[num]; for (int j = 0; j < weightForBone.Length; j++) { weightForBone[j] = 0f; } float num2 = 0f; for (int k = 0; k < num; k++) { num2 += distToBone[k]; } for (int l = 0; l < num; l++) { array2[l] = 1f - distToBone[l] / num2; } debugDists = distToBone; if (num == 1 || spread == 0f) { weightForBone[0] = 1f; return; } if (num == 2) { float num3 = 1f; weightForBone[0] = 1f; float num4 = Mathf.InverseLerp(distToBone[0] + array[0] / 1.25f * spread, distToBone[0], distToBone[1]); debugDists[0] = num4; num3 += (weightForBone[1] = DistributionIn(Mathf.Lerp(0f, 1f, num4), Mathf.Lerp(1.5f, 16f, spreadPower))); debugDistWeights = new float[weightForBone.Length]; weightForBone.CopyTo(debugDistWeights, 0); for (int m = 0; m < num; m++) { weightForBone[m] /= num3; } debugWeights = weightForBone; return; } float num5 = array[0] / 10f; float num6 = array[0] / 2f; float num7 = 0f; for (int n = 0; n < num; n++) { float t = Mathf.InverseLerp(0f, num5 + num6 * spread, distToBone[n]); float num8 = Mathf.Lerp(1f, 0f, t); if (n == 0 && num8 == 0f) { num8 = 1f; } weightForBone[n] = num8; num7 += num8; } debugDistWeights = new float[weightForBone.Length]; weightForBone.CopyTo(debugDistWeights, 0); for (int num9 = 0; num9 < num; num9++) { weightForBone[num9] /= num7; } debugWeights = weightForBone; } public static float DistributionIn(float k, float power) { return Mathf.Pow(k, power + 1f); } public static Color GetBoneIndicatorColor(int boneIndex, int bonesCount, float s = 0.9f, float v = 0.9f) { return Color.HSVToRGB(((float)boneIndex * 1.125f / (float)bonesCount + 0.125f * (float)boneIndex + 0.3f) % 1f, s, v); } public Color GetWeightColor() { Color color = GetBoneIndicatorColor(bonesIndexes[0], allMeshBonesCount, 1f, 1f); for (int i = 1; i < bonesIndexes.Length; i++) { color = Color.Lerp(color, GetBoneIndicatorColor(bonesIndexes[i], allMeshBonesCount, 1f, 1f), weights[i]); } return color; } } }