Firstborn/Assets/Daz3D/Scripts/ClothTools.cs

400 lines
14 KiB
C#
Raw Normal View History

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Cloth))]
//[ExecuteInEditMode]
public class ClothTools : MonoBehaviour
{
[SerializeField, HideInInspector]
public SkinnedMeshRenderer m_Skinned;
[SerializeField, HideInInspector]
public Cloth m_Cloth;
[System.Serializable]
class SubmeshMeta
{
public int submesh_index;
public string submesh_name;
public int vertex_offset;
public int vertex_count;
public SubmeshMeta(int index, string name, int offset, int count)
{
submesh_index = index;
submesh_name = name;
vertex_offset = offset;
vertex_count = count;
}
public int Start()
{
return vertex_offset;
}
public int Stop()
{
return vertex_offset + vertex_count + 1;
}
public bool InSubmesh(int a_index)
{
if ( a_index >= vertex_offset && a_index <= (vertex_offset+vertex_count) )
{
return true;
}
else
{
return false;
}
}
}
[SerializeField, HideInInspector]
private List<SubmeshMeta> m_SubmeshMeta;
[SerializeField, HideInInspector]
private CollapsedVertexArray m_CollapsedVerts;
[HideInInspector]
public TextAsset m_BinaryData;
[HideInInspector]
public TextAsset m_TestVertData;
void Reset()
{
m_Skinned = GetComponent<SkinnedMeshRenderer>();
m_Cloth = GetComponent<Cloth>();
m_CollapsedVerts = null;
GenerateLookupTables();
}
public void GenerateLookupTables()
{
m_CollapsedVerts = new CollapsedVertexArray(m_Skinned.sharedMesh.vertices);
if (m_Cloth.vertices.Length == m_CollapsedVerts.Length)
{
//Debug.Log("collapsed == cloth. Ready for weightmap transfer.");
}
else
{
Debug.LogError("ClothTools.GenerateLookupTables() ERROR: # collapsed verts (" + m_CollapsedVerts.Length + ") != # cloth verts(" + m_Cloth.vertices.Length + "). Please fix lookup table.");
}
// create submesh meta
m_SubmeshMeta = new List<SubmeshMeta>();
for (int i = 0; i < m_Skinned.sharedMesh.subMeshCount; i++)
{
var submesh = m_Skinned.sharedMesh.GetSubMesh(i);
string submesh_name = submesh.ToString();
if (m_Skinned.sharedMaterials.Length == m_Skinned.sharedMesh.subMeshCount)
{
submesh_name = m_Skinned.sharedMaterials[i].name;
}
m_SubmeshMeta.Add(new SubmeshMeta(i, submesh_name, submesh.firstVertex, submesh.vertexCount));
}
}
public void SetSubMeshWeights(int submesh_index, float weight_value)
{
if (m_CollapsedVerts == null || m_CollapsedVerts.Length <= 0)
{
//Debug.Log("ClothTools.SetSubMeshWeights(): Lookup tables were reset. Regenerating...");
GenerateLookupTables();
}
if (submesh_index > m_Skinned.sharedMesh.subMeshCount)
{
Debug.LogError("ClothTools.SetSubMeshWeight(): invalid submesh_index=" + submesh_index);
return;
}
ClothSkinningCoefficient[] newCoefficients = new ClothSkinningCoefficient[m_Cloth.coefficients.Length];
System.Array.Copy(m_Cloth.coefficients, newCoefficients, newCoefficients.Length);
//var submesh = m_Skinned.sharedMesh.GetSubMesh(submesh_index);
//for (int vertex_index = submesh.firstVertex; vertex_index < (submesh.firstVertex + submesh.vertexCount); vertex_index++)
//{
// int cloth_vertex = m_CollapsedVerts.LookupIndex(vertex_index);
// if (cloth_vertex != -1)
// newCoefficients[cloth_vertex].maxDistance = weight_value;
//}
var triangle_vertindex_array = m_Skinned.sharedMesh.GetTriangles(submesh_index);
bool errorOnce = false;
foreach (int vertex_index in triangle_vertindex_array)
{
int cloth_vertex = m_CollapsedVerts.LookupIndex(vertex_index);
if (cloth_vertex != -1)
{
newCoefficients[cloth_vertex].maxDistance = weight_value;
}
else
{
if (errorOnce == false)
{
errorOnce = true;
Debug.LogError("ClothTools.SetSubmeshWeights(): submesh[" + submesh_index + "] vertex index lookup did not return valid result for cloth vertex index. ");
}
}
}
m_Cloth.coefficients = newCoefficients;
}
public void ClearSubMeshWeights(int submesh_index)
{
SetSubMeshWeights(submesh_index, float.MaxValue);
}
public void ClearWeightMap()
{
if (m_Cloth == null)
return;
ClothSkinningCoefficient[] newCoefficients = new ClothSkinningCoefficient[m_Cloth.coefficients.Length];
System.Array.Copy(m_Cloth.coefficients, newCoefficients, newCoefficients.Length);
for (int i = 0; i < newCoefficients.Length; i++)
{
float maxDistance = newCoefficients[i].maxDistance;
newCoefficients[i].maxDistance = float.MaxValue;
}
m_Cloth.coefficients = newCoefficients;
}
public void LoadGradientPattern()
{
if (m_Cloth == null)
return;
ClothSkinningCoefficient[] newCoefficients = new ClothSkinningCoefficient[m_Cloth.coefficients.Length];
System.Array.Copy(m_Cloth.coefficients, newCoefficients, newCoefficients.Length);
for (int i = 0; i < newCoefficients.Length; i++)
{
float maxDistance = newCoefficients[i].maxDistance;
// float gradientValue = (float)i / newCoefficients.Length * float.MaxValue;
float gradientValue = (float)i / newCoefficients.Length;
newCoefficients[i].maxDistance = gradientValue;
}
m_Cloth.coefficients = newCoefficients;
}
public void LoadSteppedGradient()
{
if (m_Cloth == null)
return;
ClothSkinningCoefficient[] newCoefficients = new ClothSkinningCoefficient[m_Cloth.coefficients.Length];
System.Array.Copy(m_Cloth.coefficients, newCoefficients, newCoefficients.Length);
for (int i = 0; i < newCoefficients.Length; i++)
{
float maxDistance = newCoefficients[i].maxDistance;
float gradientValue = (float)i / newCoefficients.Length;
int stepping = (int) (gradientValue * 10.0f);
gradientValue = stepping / 10.0f;
newCoefficients[i].maxDistance = gradientValue;
}
m_Cloth.coefficients = newCoefficients;
}
public void SaveWeightMap(string filename)
{
ClothSkinningCoefficient[] outCoefficients = new ClothSkinningCoefficient[m_Cloth.coefficients.Length];
System.Array.Copy(m_Cloth.coefficients, outCoefficients, outCoefficients.Length);
int numVerts = outCoefficients.Length;
float[] weights = new float[numVerts];
int numBytes = sizeof(float) * numVerts;
byte[] binaryBuffer = new byte[numBytes];
for (int i=0; i < numVerts; i++)
{
weights[i] = outCoefficients[i].maxDistance;
}
System.Buffer.BlockCopy(weights, 0, binaryBuffer, 0, numBytes);
System.IO.File.WriteAllBytes(filename, binaryBuffer);
}
public void LoadWeightMap(string filename)
{
ClothSkinningCoefficient[] newCoefficients = new ClothSkinningCoefficient[m_Cloth.coefficients.Length];
System.Array.Copy(m_Cloth.coefficients, newCoefficients, newCoefficients.Length);
/////////////////////////////////////////////////////
/// Load Raw Weight Map
/////////////////////////////////////////////////////
int numVerts = newCoefficients.Length;
float[] weights = new float[numVerts];
int numBytes = sizeof(float) * numVerts;
byte[] binaryBuffer = System.IO.File.ReadAllBytes(filename);
System.Buffer.BlockCopy(binaryBuffer, 0, weights, 0, numBytes);
for (int i=0; i < numVerts; i++)
{
newCoefficients[i].maxDistance = weights[i];
}
m_Cloth.coefficients = newCoefficients;
}
public void ImportWeightMap(string filename)
{
ClothSkinningCoefficient[] newCoefficients = new ClothSkinningCoefficient[m_Cloth.coefficients.Length];
System.Array.Copy(m_Cloth.coefficients, newCoefficients, newCoefficients.Length);
/////////////////////////////////////////////////////
/// Load Raw Weight Map
/////////////////////////////////////////////////////
int numVerts = newCoefficients.Length ;
ushort[] weights = new ushort[numVerts];
int numBytes = sizeof(ushort) * numVerts;
byte[] binaryBuffer = System.IO.File.ReadAllBytes(filename);
System.Buffer.BlockCopy(binaryBuffer, 0, weights, 0, numBytes);
float simulation_strength = 0.0f;
for (int vertex_index = 0; vertex_index < numVerts; vertex_index++)
{
int cloth_index = vertex_index;
if (cloth_index >= newCoefficients.Length)
{
Debug.LogError("ClothTools.LoadRawWeightMap(): cloth_index is greater than coefficient array: " + vertex_index + " vs " + newCoefficients.Length);
break;
}
simulation_strength = (float) weights[vertex_index] / ushort.MaxValue;
//// DEBUG TESTING: set zero value (red) to maxvalue(black)
//if (simulation_strength == 0) simulation_strength = float.MaxValue;
//float strength_max = 1.0f;
//float strength_min = 0.0f;
//float strength_scale_threshold = 0.5f;
float adjusted_simulation_strength = simulation_strength;
//// tiered scaling
//if (simulation_strength <= strength_scale_threshold)
//{
// // stronger compression of values below threshold
// float scale = 0.075f;
// float offset = 0.2f;
// adjusted_simulation_strength = (simulation_strength - offset) * scale;
//}
//else
//{
// float offset = (strength_scale_threshold - 0.2f) * 0.075f; // offset = (threshold - previous tier's offset) * previous teir's scale
// float scale = 0.2f;
// adjusted_simulation_strength = (simulation_strength - offset) / (1 - offset); // apply offset, then normalize to 1.0
// adjusted_simulation_strength *= scale;
//}
//// clamp to 0.0f to 0.2f
//float coeff_min = 0.0f;
//float coeff_max = 0.2f;
//adjusted_simulation_strength = (adjusted_simulation_strength > coeff_min) ? adjusted_simulation_strength : coeff_min;
//adjusted_simulation_strength = (adjusted_simulation_strength < coeff_max) ? adjusted_simulation_strength : coeff_max;
newCoefficients[cloth_index].maxDistance = adjusted_simulation_strength;
}
m_Cloth.coefficients = newCoefficients;
}
public void TestVertData()
{
// get verts
Vector3[] unityVerts = m_Cloth.vertices;
int numVerts = m_Cloth.vertices.Length;
float[] dazVertBuffer = new float[numVerts*3];
int byte_length = sizeof(float) * numVerts*3;
Debug.Log("byte_length = " + byte_length);
System.Buffer.BlockCopy(m_TestVertData.bytes, 0, dazVertBuffer, 0, numVerts*3);
Vector3 unityMax = new Vector3();
Vector3 unityMin = new Vector3();
Vector3 dazMax = new Vector3();
Vector3 dazMin = new Vector3();
int i;
for (i=0; i < unityVerts.Length; i++)
{
Vector3 a_vert = m_Skinned.rootBone.TransformPoint(unityVerts[i]);
// Vector3 a_vert = m_Cloth.transform.TransformPoint(unityVerts[i]);
// Vector3 a_vert = unityVerts[i];
a_vert *= 100f;
// calc bounds for unity verts
unityMax.x = (a_vert.x > unityMax.x) ? a_vert.x : unityMax.x;
unityMax.y = (a_vert.y > unityMax.y) ? a_vert.y : unityMax.y;
unityMax.z = (a_vert.z > unityMax.z) ? a_vert.z : unityMax.z;
unityMin.x = (a_vert.x < unityMin.x) ? a_vert.x : unityMin.x;
unityMin.y = (a_vert.y < unityMin.y) ? a_vert.y : unityMin.y;
unityMin.z = (a_vert.z < unityMin.z) ? a_vert.z : unityMin.z;
//int j;
//for (j=0; j < numVerts; j++)
//{
// Vector3 b_vert = new Vector3();
// b_vert.x = -dazVertBuffer[(j*3)+0] * 0.01f;
// b_vert.y = dazVertBuffer[(j*3)+1] * 0.01f;
// b_vert.z = dazVertBuffer[(j*3)+2] * 0.01f;
// if (Vector3.Distance(a_vert, b_vert) < 0.001f)
// {
// Debug.Log("unity[" + i + "] == daz[" + j + "]");
// break;
// }
//}
//if (j == numVerts)
//{
// Debug.LogError("Could not match skinned[" + i + "] in any vertex of daz[]");
// calcDazBounds = false;
//}
}
int j;
for (j = 0; j < numVerts; j++)
{
Vector3 a_vert = new Vector3();
a_vert.y = dazVertBuffer[(j * 3) + 0] * 0.95830578062345271389800693281935f;
a_vert.x = dazVertBuffer[(j * 3) + 1] * 0.7561518763918325407088556644264f;
a_vert.z = dazVertBuffer[(j * 3) + 2] * 1.1470080563670463526164516598318f + 14.86038f;
// calc bounds for unity verts
dazMax.x = (a_vert.x > dazMax.x) ? a_vert.x : dazMax.x;
dazMax.y = (a_vert.y > dazMax.y) ? a_vert.y : dazMax.y;
dazMax.z = (a_vert.z > dazMax.z) ? a_vert.z : dazMax.z;
dazMin.x = (a_vert.x < dazMin.x) ? a_vert.x : dazMin.x;
dazMin.y = (a_vert.y < dazMin.y) ? a_vert.y : dazMin.y;
dazMin.z = (a_vert.z < dazMin.z) ? a_vert.z : dazMin.z;
}
Debug.Log("unityBounds: (" + unityMin.x + " to " + unityMax.x + " [" + (unityMax.x - unityMin.x) + "], " + unityMin.y + " to " + unityMax.y + " [" + (unityMax.y - unityMin.y) + "], " + unityMin.z + " to " + unityMax.z + " [" + (unityMax.z - unityMin.z) + "])");
Debug.Log("dazBounds: (" + dazMin.x + " to " + dazMax.x + " [" + (dazMax.x - dazMin.x) + "], " + dazMin.y + " to " + dazMax.y + " [" + (dazMax.y - dazMin.y) + "], " + dazMin.z + " to " + dazMax.z + " [" + (dazMax.z - dazMin.z) + "])");
Debug.Log("Done");
}
}