using System; using System.Collections.Generic; using UnityEngine; namespace SpriteViewer { public class DynamicClothBone : MonoBehaviour { public static float InvSqrtFast(Vector3 f_vSrc) { float num = f_vSrc.x * f_vSrc.x + f_vSrc.y * f_vSrc.y + f_vSrc.z * f_vSrc.z; float num2 = 0.5f * num; int num3 = (int)num; num3 = 1597463174 - (num3 >> 1); num = (float)num3; num *= 1.5f - num2 * num * num; return 1f / num; } public Vertex[] vertices { get { return this._vertices; } } public Triangle[] triangles { get { return this._triangles; } } private void Start() { this._gridSize = this.gridSize * this.SimScale; int num = this._gridSize * this._gridSize; int num2 = (this._gridSize - 1) * this._gridSize * 2; num2 += (this._gridSize - 1) * (this._gridSize - 1) * 2; num2 += (this._gridSize - 2) * this._gridSize * 2; this._particles = new ClothParticle[num]; this._springs = new ClothSpring[num2]; this.InitMesh(); this.UpdateParameters(); this._Reset(); } private void UpdateParameters() { this._gravity = this.Gravity * (float)this.SimScale; this._StretchStiffness = this.StretchStiffness * this.clothScale; this._BendStiffness = 1f * this.clothScale; this._mass = this.mass * (float)this.SimScale; } private void InitMesh() { int num = this._gridSize * this._gridSize * 2; this._triangles = new Triangle[num]; int num2 = this._gridSize * this._gridSize; this._vertices = new Vertex[num2]; int num3 = 0; for (int i = 0; i < this._gridSize - 1; i++) { for (int j = 0; j < this._gridSize - 1; j++) { int c = i * this._gridSize + j; int num4 = i * this._gridSize + j + 1; int a = (i + 1) * this._gridSize + j; int b = (i + 1) * this._gridSize + j + 1; this._triangles[num3].A = a; this._triangles[num3].B = num4; this._triangles[num3].C = c; num3++; this._triangles[num3].A = a; this._triangles[num3].B = b; this._triangles[num3].C = num4; num3++; } } for (int k = 0; k < this._gridSize; k++) { for (int l = 0; l < this._gridSize; l++) { int num5 = k * this._gridSize + l; this._vertices[num5].uv = new Vector2((float)l / (float)this._gridSize, (float)k / (float)this._gridSize); } } } public void _Reset() { for (int i = 0; i < this._gridSize; i++) { for (int j = 0; j < this._gridSize; j++) { float num = (float)j / (float)(this._gridSize - 1) - 0.5f; float num2 = (float)i / (float)(this._gridSize - 1) - 0.5f; int num3 = i * this._gridSize + j; this._particles[num3].currentPosition = new Vector3(this.clothScale * num, 8.5f, this.clothScale * num2); this._particles[num3].currentVelocity = Vector3.zero; this._particles[num3].defaultLocalPosition = this._particles[num3].currentPosition + base.transform.position; this._particles[num3].inverseMass = 1f / this._mass; this._particles[num3].pinned = false; this._particles[num3].tension = Vector3.zero; } } float magnitude = (this._particles[0].currentPosition - this._particles[1].currentPosition).magnitude; this._particles[0].pinned = true; this._particles[this._gridSize - 1].pinned = true; this._particles[this._gridSize * (this._gridSize - 1)].pinned = true; this._particles[this._gridSize * this._gridSize - 1].pinned = true; int num4 = 0; for (int k = 0; k < this._gridSize; k++) { for (int l = 0; l < this._gridSize - 1; l++) { this._springs[num4] = new ClothSpring(k * this._gridSize + l, k * this._gridSize + l + 1, magnitude, this._StretchStiffness); num4++; } } for (int m = 0; m < this._gridSize - 1; m++) { for (int n = 0; n < this._gridSize; n++) { this._springs[num4] = new ClothSpring(m * this._gridSize + n, (m + 1) * this._gridSize + n, magnitude, this._StretchStiffness); num4++; } } for (int num5 = 0; num5 < this._gridSize - 1; num5++) { for (int num6 = 0; num6 < this._gridSize - 1; num6++) { this._springs[num4] = new ClothSpring(num5 * this._gridSize + num6, (num5 + 1) * this._gridSize + num6 + 1, magnitude * (float)Math.Sqrt(2.0), this._BendStiffness); num4++; } } for (int num7 = 0; num7 < this._gridSize - 1; num7++) { for (int num8 = 1; num8 < this._gridSize; num8++) { this._springs[num4] = new ClothSpring(num7 * this._gridSize + num8, (num7 + 1) * this._gridSize + num8 - 1, magnitude * (float)Math.Sqrt(2.0), this._BendStiffness); num4++; } } for (int num9 = 0; num9 < this._gridSize; num9++) { for (int num10 = 0; num10 < this._gridSize - 2; num10++) { this._springs[num4] = new ClothSpring(num9 * this._gridSize + num10, num9 * this._gridSize + num10 + 2, magnitude * 2f, this._BendStiffness); num4++; } } for (int num11 = 0; num11 < this._gridSize - 2; num11++) { for (int num12 = 0; num12 < this._gridSize; num12++) { this._springs[num4] = new ClothSpring(num11 * this._gridSize + num12, (num11 + 2) * this._gridSize + num12, magnitude * 2f, this._BendStiffness); num4++; } } this.UpdateMesh(); } private static Vector3 CalculateNormal(Vector3 VA, Vector3 VB, Vector3 VC) { Vector3 lhs = VB - VA; Vector3 rhs = VC - VA; Vector3 result = Vector3.Cross(lhs, rhs); result.Normalize(); return result; } private void UpdateMesh() { for (int i = 0; i < this._triangles.Length; i++) { Triangle triangle = this._triangles[i]; Vector3 position = this.vertices[triangle.A].position; Vector3 position2 = this.vertices[triangle.B].position; Vector3 position3 = this.vertices[triangle.C].position; this._triangles[i].normal = DynamicClothBone.CalculateNormal(position, position2, position3); } for (int j = 0; j < this._gridSize; j++) { for (int k = 0; k < this._gridSize; k++) { int num = j * this._gridSize + k; Vector3 vector = Vector3.zero; int num2 = 0; for (int l = 0; l <= 1; l++) { for (int m = 0; m <= 1; m++) { if (m + k < this._gridSize && l + j < this._gridSize) { int num3 = (j + l) * this._gridSize + (k + m) * 2; vector += this._triangles[num3].normal; num3++; vector += this._triangles[num3].normal; num2 += 2; } } } vector /= (float)num2; this._vertices[num].normal = vector; } } for (int n = 0; n < this._gridSize; n++) { for (int num4 = 0; num4 < this._gridSize; num4++) { int num5 = n * this._gridSize + num4; this._vertices[num5].position = this._particles[num5].currentPosition; } } } private void Update() { for (int i = 0; i < this._particles.Length; i++) { if (this._particles[i].pinned) { this._particles[i].currentPosition = base.transform.position + this._particles[i].defaultLocalPosition; this._particles[i].nextVelocity = Vector3.zero; } } } private void LateUpdate() { float unscaledDeltaTime = Time.unscaledDeltaTime; if (unscaledDeltaTime <= 0f) { return; } this._timeSinceLastUpdate += unscaledDeltaTime; bool flag = false; float d = this.minimumPhysicsDelta; while (this._timeSinceLastUpdate > this.minimumPhysicsDelta) { this._timeSinceLastUpdate -= this.minimumPhysicsDelta; flag = true; for (int i = 0; i < this._springs.Length; i++) { Vector3 vector = this._particles[this._springs[i].P1].currentPosition - this._particles[this._springs[i].P2].currentPosition; float magnitude = vector.magnitude; float num = magnitude - this._springs[i]._NaturalLength; float num2 = this._springs[i]._Stiffness * (num * this._springs[i]._InverseLength); vector *= num2 / magnitude; ClothParticle[] particles = this._particles; int p = this._springs[i].P2; particles[p].tension = particles[p].tension + vector; ClothParticle[] particles2 = this._particles; int p2 = this._springs[i].P1; particles2[p2].tension = particles2[p2].tension - vector; } for (int j = 0; j < this._particles.Length; j++) { if (this._particles[j].pinned) { this._particles[j].nextPosition = this._particles[j].currentPosition; this._particles[j].nextVelocity = Vector3.zero; } else { Vector3 vector2 = this._gravity + this._particles[j].tension; Vector3 a = vector2 * this._particles[j].inverseMass; this._particles[j].nextVelocity = this._particles[j].currentVelocity + a * d; ClothParticle[] particles3 = this._particles; int num3 = j; particles3[num3].nextVelocity = particles3[num3].nextVelocity * this.dampFactor; vector2 = this._particles[j].nextVelocity * d; this._particles[j].nextPosition = this._particles[j].currentPosition + vector2; for (int k = 0; k < this._colliders.Count; k++) { Vector3 a2 = this._particles[j].nextPosition - this._colliders[k].Position; float num4 = this._colliders[k].Radius * 1.08f; if (a2.sqrMagnitude < num4 * num4) { a2.Normalize(); a2 *= num4; this._particles[j].nextPosition = a2 + this._colliders[k].Position; this._particles[j].nextVelocity = Vector3.zero; break; } } } } for (int l = 0; l < this._particles.Length; l++) { this._particles[l].currentPosition = this._particles[l].nextPosition; this._particles[l].currentVelocity = this._particles[l].nextVelocity; this._particles[l].tension = Vector3.zero; } } if (flag) { this.UpdateMesh(); } } public void AddCollider(Vector3 position, float radius) { ClothCollider item = new ClothCollider(position, radius); this._colliders.Add(item); } public void UnpinParticle(int index) { this._particles[index].pinned = false; } private void OnValidate() { if (Application.isPlaying && this._particles != null && this._springs != null && this._triangles != null) { this.UpdateParameters(); this._Reset(); } } private void OnDrawGizmosSelected() { if (this._particles != null) { for (int i = 0; i < this._particles.Length; i++) { Gizmos.DrawWireSphere(this._particles[i].currentPosition, 0.01f); } } } public int SimScale = 1; public float minimumPhysicsDelta = 0.01f; public float clothScale = 20f; public float StretchStiffness = 2.5f; private float _StretchStiffness; public float BendStiffness = 1f; private float _BendStiffness; public float mass = 0.01f; private float _mass; public float dampFactor = 0.9f; public int gridSize = 13; private int _gridSize; private ClothSpring[] _springs; private ClothParticle[] _particles; private float _timeSinceLastUpdate; public Vector3 Gravity = new Vector3(0f, -0.98f, 0f); private Vector3 _gravity; private List _colliders = new List(); private Vertex[] _vertices; private Triangle[] _triangles; } }