BoundedBiharmonicWeightsGenerator.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using UnityEngine;
  5. namespace UnityEditor.U2D.Animation
  6. {
  7. internal class BoundedBiharmonicWeightsGenerator : IWeightsGenerator
  8. {
  9. internal static readonly BoneWeight defaultWeight = new BoneWeight() { weight0 = 1 };
  10. private const int kNumIterations = -1;
  11. private const int kNumSamples = 10;
  12. private const float kMinAngle = 20f;
  13. private const float kLargestTriangleAreaFactor = 0.25f;
  14. private const float kMeshAreaFactor = 0.0015f;
  15. [DllImport("BoundedBiharmonicWeightsModule")]
  16. private static extern int Bbw(int iterations,
  17. [In, Out] IntPtr vertices, int vertexCount, int originalVertexCount,
  18. [In, Out] IntPtr indices, int indexCount,
  19. [In, Out] IntPtr controlPoints, int controlPointsCount,
  20. [In, Out] IntPtr boneEdges, int boneEdgesCount,
  21. [In, Out] IntPtr pinIndices, int pinIndexCount,
  22. [In, Out] IntPtr weights
  23. );
  24. public BoneWeight[] Calculate(Vector2[] vertices, Edge[] edges, Vector2[] controlPoints, Edge[] bones, int[] pins)
  25. {
  26. var weights = new BoneWeight[vertices.Length];
  27. for (var i = 0; i < weights.Length; ++i)
  28. weights[i] = defaultWeight;
  29. var indices = new List<int>(vertices.Length);
  30. TriangulationUtility.Triangulate(vertices, edges, indices);
  31. if (indices.Count < 3)
  32. return weights;
  33. var boneSamples = SampleBones(controlPoints, bones, kNumSamples);
  34. var verticesList = new List<Vector2>(vertices.Length + controlPoints.Length + boneSamples.Length);
  35. var edgesList = new List<Edge>(edges);
  36. var indicesList = new List<int>();
  37. verticesList.AddRange(vertices);
  38. verticesList.AddRange(controlPoints);
  39. verticesList.AddRange(boneSamples);
  40. try
  41. {
  42. TriangulationUtility.Tessellate(kMinAngle, 0f, kMeshAreaFactor, kLargestTriangleAreaFactor, 0, verticesList, edgesList, indicesList);
  43. }
  44. catch (Exception)
  45. {
  46. return weights;
  47. }
  48. var tessellatedVertices = verticesList.ToArray();
  49. var tessellatedIndices = indicesList.ToArray();
  50. GCHandle verticesHandle = GCHandle.Alloc(tessellatedVertices, GCHandleType.Pinned);
  51. GCHandle indicesHandle = GCHandle.Alloc(tessellatedIndices, GCHandleType.Pinned);
  52. GCHandle controlPointsHandle = GCHandle.Alloc(controlPoints, GCHandleType.Pinned);
  53. GCHandle bonesHandle = GCHandle.Alloc(bones, GCHandleType.Pinned);
  54. GCHandle pinsHandle = GCHandle.Alloc(pins, GCHandleType.Pinned);
  55. GCHandle weightsHandle = GCHandle.Alloc(weights, GCHandleType.Pinned);
  56. Bbw(kNumIterations,
  57. verticesHandle.AddrOfPinnedObject(), tessellatedVertices.Length, vertices.Length,
  58. indicesHandle.AddrOfPinnedObject(), tessellatedIndices.Length,
  59. controlPointsHandle.AddrOfPinnedObject(), controlPoints.Length,
  60. bonesHandle.AddrOfPinnedObject(), bones.Length,
  61. pinsHandle.AddrOfPinnedObject(), pins.Length,
  62. weightsHandle.AddrOfPinnedObject());
  63. verticesHandle.Free();
  64. indicesHandle.Free();
  65. controlPointsHandle.Free();
  66. bonesHandle.Free();
  67. pinsHandle.Free();
  68. weightsHandle.Free();
  69. for (var i = 0; i < weights.Length; ++i)
  70. {
  71. var weight = weights[i];
  72. if (weight.Sum() == 0f)
  73. weights[i] = defaultWeight;
  74. }
  75. return weights;
  76. }
  77. public void DebugMesh(ISpriteMeshData spriteMeshData, Vector2[] vertices, Edge[] edges, Vector2[] controlPoints, Edge[] bones, int[] pins)
  78. {
  79. var boneSamples = SampleBones(controlPoints, bones, kNumSamples);
  80. var verticesList = new List<Vector2>(vertices.Length + controlPoints.Length + boneSamples.Length);
  81. var edgesList = new List<Edge>(edges);
  82. var indicesList = new List<int>();
  83. verticesList.AddRange(vertices);
  84. verticesList.AddRange(controlPoints);
  85. verticesList.AddRange(boneSamples);
  86. TriangulationUtility.Tessellate(kMinAngle, 0f, kMeshAreaFactor, kLargestTriangleAreaFactor, 0, verticesList, edgesList, indicesList);
  87. spriteMeshData.Clear();
  88. verticesList.ForEach(v => spriteMeshData.AddVertex(v, new BoneWeight()));
  89. spriteMeshData.edges.AddRange(edgesList);
  90. spriteMeshData.indices.AddRange(indicesList);
  91. }
  92. private Vector2[] SampleBones(Vector2[] points, Edge[] edges, int numSamples)
  93. {
  94. Debug.Assert(numSamples > 0);
  95. var sampledEdges = new List<Vector2>();
  96. for (var i = 0; i < edges.Length; i++)
  97. {
  98. var edge = edges[i];
  99. var tip = points[edge.index1];
  100. var tail = points[edge.index2];
  101. var length = (tip - tail).magnitude;
  102. for (var s = 0; s < numSamples; s++)
  103. {
  104. var f = (s + 1f) / (float)(numSamples + 1f);
  105. sampledEdges.Add(f * tail + (1f - f) * tip);
  106. }
  107. }
  108. return sampledEdges.ToArray();
  109. }
  110. }
  111. }