public void ComputeSpringForces() { ClothNode p1node = P1.GetComponent <ClothNode>(); ClothNode p2node = P2.GetComponent <ClothNode>(); Vector3 displacement = P2.transform.position - P1.transform.position; float distance = displacement.magnitude; Vector3 direction = displacement / distance; // 1 Dimension velocities b/c a spring exists in 1 Dimension // Used in Dampen Force formula float node1Velocity = Vector3.Dot(displacement.normalized, p1node.velocity); float node2Velocity = Vector3.Dot(displacement.normalized, p2node.velocity); // Spring Force = -spring factor * (distance - rest length) float Fspring = -springConstant * (distance - restLength); // Dampen Force = -Dampen Factor * (difference of velocity) float Fdampen = -damperConstant * (node2Velocity - node1Velocity); // 1 Dimension Spring Dampen Force // Sum of Spring Force and Dampen Force float SpringDampenforce = Fspring + Fdampen; // Converting it back into a 3 Dimensional force Vector3 p2force = SpringDampenforce * direction; Vector3 p1force = -p2force; // Applying it to nodes p1node.force += p1force; p2node.force += p2force; }
public void ComputeTriangleForces(Vector3 air_Velocity, float density, float drag) { ClothNode a = nodeA.GetComponent <ClothNode>(); ClothNode b = nodeB.GetComponent <ClothNode>(); ClothNode c = nodeC.GetComponent <ClothNode>(); Vector3 triangleVelocity = (a.velocity + b.velocity + c.velocity) / 3; triangleVelocity -= air_Velocity; Vector3 p1 = a.transform.position; Vector3 p2 = b.transform.position; Vector3 p3 = c.transform.position; Vector3 r2r1crossr3r1 = Vector3.Cross((p1 - p2), (p3 - p2)); Vector3 normal = r2r1crossr3r1 / r2r1crossr3r1.magnitude; float area = (0.5f * Vector3.Dot(triangleVelocity, normal) * triangleVelocity.magnitude) / r2r1crossr3r1.magnitude; Vector3 forceAero = -0.5f * drag * density * area * r2r1crossr3r1; forceAero /= 3.0f; if (!a.TouchingFloor()) { a.force += forceAero; } if (!b.TouchingFloor()) { b.force += forceAero; } if (!c.TouchingFloor()) { c.force += forceAero; } }
void Start() { nodes = new ClothNode[row * col]; vert = new Vector3[row * col]; uv = new Vector2[row * col]; tris = new int[(row - 1) * (col - 1) * 2 * 3]; for (int i = 0; i < row; ++i) { for (int j = 0; j < col; ++j) { Vector3 initPos = new Vector3(j, -i, 0) / 10; vert[i * col + j] = initPos; var node = new ClothNode(); node.r_prev = initPos; node.r_now = initPos; nodes[i * col + j] = node; node.isStatic = (i == 0); uv[i * col + j] = new Vector2(map(j, 0, (col - 1), 0, 1), map(-i, 0, -(row - 1), 1, 0)); } } gameObject.AddComponent <MeshRenderer>().material = mat; var meshFilter = gameObject.AddComponent <MeshFilter>(); mesh = meshFilter.mesh; UpdateMesh(); }
public void Parse(Stream input) { using (BinaryReader reader = new BinaryReader(input)) { Header = reader.Read <ClothHeader>(); if (Header.Offset > 0) { reader.BaseStream.Position = Header.Offset; Descriptors = new ClothDesc[Header.Count]; Nodes = new ClothNode[Header.Count][]; NodeBones = new Dictionary <int, short> [Header.Count]; for (ulong i = 0; i < Header.Count; i++) { Descriptors[i] = reader.Read <ClothDesc>(); long nextStartPos = reader.BaseStream.Position; if (Descriptors[i].Section8Offset != 4574069944263674675) // todo: wtf { reader.BaseStream.Position = Descriptors[i].Section8Offset; NodeBones[i] = new Dictionary <int, short>(); for (int nodeIndex = 0; nodeIndex < Descriptors[i].DriverNodeCount; nodeIndex++) { NodeBones[i][nodeIndex] = reader.ReadInt16(); } } if (Descriptors[i].Section1Offset > 0 && Descriptors[i].Section1Offset != 4692750811720056850) // todo: wtf2 { Nodes[i] = new ClothNode[Descriptors[i].DriverNodeCount]; reader.BaseStream.Position = Descriptors[i].Section1Offset; for (int nodeIndex = 0; nodeIndex < Descriptors[i].DriverNodeCount; nodeIndex++) { Nodes[i][nodeIndex] = new ClothNode(reader); } } reader.BaseStream.Position = nextStartPos; } } } }
public void Parse(Stream input) { using (BinaryReader reader = new BinaryReader(input, Encoding.UTF8, true)) { Header = reader.Read <HeaderInfo>(); if (Header.descCount > 0) { Descriptors = new ClothDesc[Header.descCount]; input.Position = Header.descOffset; Nodes = new ClothNode[Header.descCount][]; BoneMap = new Dictionary <int, int> [Header.descCount]; NodeBones = new Dictionary <int, short> [Header.descCount]; for (ulong i = 0; i < Header.descCount; ++i) { Descriptors[i] = reader.Read <ClothDesc>(); long afterpos = reader.BaseStream.Position; if (Descriptors[i].section8Offset != 4574069944263674675) { reader.BaseStream.Position = Descriptors[i].section8Offset; NodeBones[i] = new Dictionary <int, short>(); for (int nodeIndex = 0; nodeIndex < Descriptors[i].driverNodeCount; nodeIndex++) { NodeBones[i][nodeIndex] = reader.ReadInt16(); } } Nodes[i] = new ClothNode[Descriptors[i].driverNodeCount]; reader.BaseStream.Position = Descriptors[i].section1Offset; for (int nodeIndex = 0; nodeIndex < Descriptors[i].driverNodeCount; nodeIndex++) { long nodeStart = reader.BaseStream.Position; float x = reader.ReadSingle(); float y = reader.ReadSingle(); float z = reader.ReadSingle(); uint zero = reader.ReadUInt32(); // zero float x2 = reader.ReadSingle(); float y2 = reader.ReadSingle(); float z2 = reader.ReadSingle(); if (zero != 0) { throw new InvalidDataException($"HTLC: zero != 0 ({zero})"); } if (Math.Abs(x - x2) > 0.01 || Math.Abs(y - y2) > 0.01 || Math.Abs(z - z2) > 0.01) { throw new InvalidDataException($"HTLC: location is different: {x}:{x2} {y}:{y2} {z}:{z2}"); } reader.BaseStream.Position = nodeStart + 0x15c; short ind1 = reader.ReadInt16(); short ind2 = reader.ReadInt16(); short ind3 = reader.ReadInt16(); short ind4 = reader.ReadInt16(); reader.BaseStream.Position = nodeStart + 0x170; float weight1 = reader.ReadSingle(); float weight2 = reader.ReadSingle(); float weight3 = reader.ReadSingle(); float weight4 = reader.ReadSingle(); reader.BaseStream.Position = nodeStart + 0x140; float verticalParentStrength1 = reader.ReadSingle(); reader.BaseStream.Position = nodeStart + 0x148; float verticalParentStrength2 = reader.ReadSingle(); reader.BaseStream.Position = nodeStart + 0x154; float diagonalParentStrength = reader.ReadSingle(); reader.BaseStream.Position = nodeStart + 0x14c; short verticalParent = reader.ReadInt16(); reader.BaseStream.Position = nodeStart + 0x158; short diagonalParent = reader.ReadInt16(); reader.BaseStream.Position = nodeStart + 0x150; short chainNumber = reader.ReadInt16(); reader.BaseStream.Position = nodeStart + 0x15a; byte isChild = reader.ReadByte(); if (isChild == 1 && chainNumber == -1) { throw new InvalidDataException("HTLC: node is child but not in a chain"); } reader.BaseStream.Position = nodeStart + 0xC0 + 16; Matrix3x4 ff = reader.Read <Matrix3x4B>().ToOpenTK(); // this is wrong... reader.BaseStream.Position = nodeStart + 0x180; Nodes[i][nodeIndex] = new ClothNode { ID = nodeIndex, X = x, Y = y, Z = z, ChainNumber = chainNumber, DiagonalParent = diagonalParent, VerticalParent = verticalParent, Bones = new [] { new ClothNodeWeight(ind1, weight1), new ClothNodeWeight(ind2, weight2), new ClothNodeWeight(ind3, weight3), new ClothNodeWeight(ind4, weight4) }, IsChild = isChild == 1, Matrix = ff }; } reader.BaseStream.Position = afterpos; } } } }