Files
HauntedBloodlines/Assets/Obi/Scripts/Cloth/Blueprints/ObiSkinnedClothBlueprint.cs
2025-05-29 22:31:40 +03:00

138 lines
5.1 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
namespace Obi
{
[CreateAssetMenu(fileName = "skinned cloth blueprint", menuName = "Obi/Skinned Cloth Blueprint", order = 122)]
public class ObiSkinnedClothBlueprint : ObiClothBlueprint
{
public override bool usesTethers
{
get { return true; }
}
protected override IEnumerator Initialize(){
if (inputMesh == null || !inputMesh.isReadable)
{
// TODO: return an error in the coroutine.
Debug.LogError("The input mesh is null, or not readable.");
yield break;
}
ClearParticleGroups();
topology = new HalfEdgeMesh();
topology.inputMesh = inputMesh;
topology.Generate();
positions = new Vector3[topology.vertices.Count];
restPositions = new Vector4[topology.vertices.Count];
velocities = new Vector3[topology.vertices.Count];
invMasses = new float[topology.vertices.Count];
principalRadii = new Vector3[topology.vertices.Count];
filters = new int[topology.vertices.Count];
colors = new Color[topology.vertices.Count];
areaContribution = new float[topology.vertices.Count];
// Create a particle for each vertex:
m_ActiveParticleCount = topology.vertices.Count;
for (int i = 0; i < topology.vertices.Count; i++)
{
HalfEdgeMesh.Vertex vertex = topology.vertices[i];
// Get the particle's area contribution.
areaContribution[i] = 0;
foreach (HalfEdgeMesh.Face face in topology.GetNeighbourFacesEnumerator(vertex))
{
areaContribution[i] += topology.GetFaceArea(face) / 3;
}
// Get the shortest neighbour edge, particle radius will be half of its length.
float minEdgeLength = Single.MaxValue;
foreach (HalfEdgeMesh.HalfEdge edge in topology.GetNeighbourEdgesEnumerator(vertex))
{
// vertices at each end of the edge:
Vector3 v1 = Vector3.Scale(scale, topology.vertices[topology.GetHalfEdgeStartVertex(edge)].position);
Vector3 v2 = Vector3.Scale(scale,topology.vertices[edge.endVertex].position);
minEdgeLength = Mathf.Min(minEdgeLength, Vector3.Distance(v1, v2));
}
invMasses[i] = (/*skinnedMeshRenderer == null &&*/ areaContribution[i] > 0) ? (1.0f / (DEFAULT_PARTICLE_MASS * areaContribution[i])) : 0;
positions[i] = Vector3.Scale(scale,vertex.position);
restPositions[i] = positions[i];
restPositions[i][3] = 1; // activate rest position.
principalRadii[i] = Vector3.one * minEdgeLength * 0.5f;
filters[i] = ObiUtils.MakeFilter(ObiUtils.CollideWithEverything, 1);
colors[i] = Color.white;
if (i % 500 == 0)
yield return new CoroutineJob.ProgressInfo("ObiCloth: generating particles...", i / (float)topology.vertices.Count);
}
colorizer = new GraphColoring(m_ActiveParticleCount);
IEnumerator dt = GenerateDeformableTriangles();
while (dt.MoveNext())
yield return dt.Current;
//Create distance constraints:
IEnumerator dc = CreateDistanceConstraints();
while (dc.MoveNext())
yield return dc.Current;
// Create aerodynamic constraints:
IEnumerator ac = CreateAerodynamicConstraints();
while (ac.MoveNext())
yield return ac.Current;
//Create bending constraints:
IEnumerator bc = CreateBendingConstraints();
while (bc.MoveNext())
yield return bc.Current;
// Create skin constraints:
IEnumerator sc = CreateSkinConstraints();
while (sc.MoveNext())
yield return sc.Current;
}
protected IEnumerator CreateSkinConstraints()
{
skinConstraintsData = new ObiSkinConstraintsData();
ObiSkinConstraintsBatch skinBatch = new ObiSkinConstraintsBatch();
skinConstraintsData.AddBatch(skinBatch);
for (int i = 0; i < topology.vertices.Count; ++i)
{
skinBatch.AddConstraint(i, Vector3.Scale(scale,topology.vertices[i].position), Vector3.up, 0.05f, 0.1f, 0, 0);
skinBatch.activeConstraintCount++;
if (i % 500 == 0)
yield return new CoroutineJob.ProgressInfo("ObiCloth: generating skin constraints...", i / (float)topology.vertices.Count);
}
Vector3[] normals = topology.inputMesh.normals;
for (int i = 0; i < normals.Length; ++i)
{
skinBatch.skinNormals[topology.rawToWelded[i]] = normals[i];
}
}
}
}