A game about forced loneliness, made by TACStudios
at master 676 lines 26 kB view raw
1using System; 2using System.Collections.Generic; 3using Unity.Mathematics; 4using UnityEngine; 5using UnityEditor.U2D.Sprites; 6using Unity.Jobs; 7using Unity.Collections; 8 9namespace UnityEditor.U2D.Animation 10{ 11 internal struct WeightedTriangle : IComparable<WeightedTriangle> 12 { 13 public int p1; 14 public int p2; 15 public int p3; 16 public float weight; 17 18 public int CompareTo(WeightedTriangle other) 19 { 20 return weight.CompareTo(other.weight); 21 } 22 } 23 24 internal struct SpriteJobData 25 { 26 public BaseSpriteMeshData spriteMesh; 27 public NativeArray<float2> vertices; 28 public NativeArray<int2> edges; 29 public NativeArray<int> indices; 30 public NativeArray<BoneWeight> weights; 31 public NativeArray<int4> result; 32 }; 33 34 internal class SpriteMeshDataController 35 { 36 public BaseSpriteMeshData spriteMeshData; 37 float2[] m_VerticesTemp = new float2[0]; 38 int2[] m_EdgesTemp = new int2[0]; 39 40 public void CreateVertex(Vector2 position) 41 { 42 CreateVertex(position, -1); 43 } 44 45 public void CreateVertex(Vector2 position, int edgeIndex) 46 { 47 Debug.Assert(spriteMeshData != null, "Assert failed. Expected: spriteMeshData != null. Actual: spriteMeshData == null"); 48 49 spriteMeshData.AddVertex(position, default(BoneWeight)); 50 51 if (edgeIndex != -1) 52 { 53 var edge = spriteMeshData.edges[edgeIndex]; 54 RemoveEdge(edge); 55 CreateEdge(edge.x, spriteMeshData.vertexCount - 1); 56 CreateEdge(edge.y, spriteMeshData.vertexCount - 1); 57 } 58 } 59 60 public void CreateEdge(int index1, int index2) 61 { 62 Debug.Assert(spriteMeshData != null, "Assert failed. Expected: spriteMeshData != null. Actual: spriteMeshData == null"); 63 Debug.Assert(index1 >= 0, $"Assert failed. Expected: index1 >= 0. Actual: index1 == {index1}"); 64 Debug.Assert(index2 >= 0, $"Assert failed. Expected: index2 >= 0. Actual: index2 == {index2}"); 65 Debug.Assert(index1 < spriteMeshData.vertexCount, $"Assert failed. Expected: index1 < spriteMeshData.vertexCount. Actual: index1 == {index1} spriteMeshData.vertexCount == {spriteMeshData.vertexCount}"); 66 Debug.Assert(index2 < spriteMeshData.vertexCount, $"Assert failed. Expected: index2 < spriteMeshData.vertexCount. Actual: index2 == {index2} spriteMeshData.vertexCount == {spriteMeshData.vertexCount}"); 67 Debug.Assert(index1 != index2, $"Assert failed. Expected: index1 != index2. Actual: index1 == {index1} index2 == {index2}"); 68 69 var newEdge = new int2(index1, index2); 70 if (!spriteMeshData.edges.ContainsAny(newEdge)) 71 { 72 var listOfEdges = new List<int2>(spriteMeshData.edges) 73 { 74 newEdge 75 }; 76 spriteMeshData.SetEdges(listOfEdges.ToArray()); 77 } 78 } 79 80 public void RemoveVertex(int index) 81 { 82 Debug.Assert(spriteMeshData != null); 83 84 //We need to delete the edges that reference the index 85 if (FindEdgesContainsIndex(index, out var edgesWithIndex)) 86 { 87 //If there are 2 edges referencing the same index we are removing, we can create a new one that connects the endpoints ("Unsplit"). 88 if (edgesWithIndex.Count == 2) 89 { 90 var first = edgesWithIndex[0]; 91 var second = edgesWithIndex[1]; 92 93 int index1 = first.x != index ? first.x : first.y; 94 int index2 = second.x != index ? second.x : second.y; 95 96 CreateEdge(index1, index2); 97 } 98 99 //remove found edges 100 for (int i = 0; i < edgesWithIndex.Count; i++) 101 { 102 RemoveEdge(edgesWithIndex[i]); 103 } 104 } 105 106 //Fix indices in edges greater than the one we are removing 107 for (int i = 0; i < spriteMeshData.edges.Length; i++) 108 { 109 var edge = spriteMeshData.edges[i]; 110 111 if (edge.x > index) 112 edge.x--; 113 if (edge.y > index) 114 edge.y--; 115 116 spriteMeshData.edges[i] = edge; 117 } 118 119 spriteMeshData.RemoveVertex(index); 120 } 121 122 public void RemoveVertex(IEnumerable<int> indices) 123 { 124 var sortedIndexList = new List<int>(indices); 125 126 if (sortedIndexList.Count == 0) 127 return; 128 129 sortedIndexList.Sort(); 130 131 for (var i = sortedIndexList.Count - 1; i >= 0; --i) 132 { 133 RemoveVertex(sortedIndexList[i]); 134 } 135 } 136 137 void RemoveEdge(int2 edge) 138 { 139 Debug.Assert(spriteMeshData != null); 140 var listOfEdges = new List<int2>(spriteMeshData.edges); 141 listOfEdges.Remove(edge); 142 spriteMeshData.SetEdges(listOfEdges.ToArray()); 143 } 144 145 bool FindEdgesContainsIndex(int index, out List<int2> result) 146 { 147 Debug.Assert(spriteMeshData != null); 148 149 bool found = false; 150 151 result = new List<int2>(); 152 153 for (int i = 0; i < spriteMeshData.edges.Length; ++i) 154 { 155 var edge = spriteMeshData.edges[i]; 156 if (edge.x == index || edge.y == index) 157 { 158 found = true; 159 result.Add(edge); 160 } 161 } 162 163 return found; 164 } 165 166 public void CreateQuad() 167 { 168 var frame = new Rect(Vector2.zero, spriteMeshData.frame.size); 169 var verts = new Vector2[] 170 { 171 new Vector2(frame.xMin, frame.yMin), 172 new Vector2(frame.xMax, frame.yMin), 173 new Vector2(frame.xMin, frame.yMax), 174 new Vector2(frame.xMax, frame.yMax) 175 }; 176 177 for (var i = 0; i < verts.Length; ++i) 178 CreateVertex(verts[i]); 179 180 var tris = new int[] 181 { 182 0, 2, 3, 1 183 }; 184 185 for (var i = 0; i < tris.Length; ++i) 186 { 187 var n = (i + 1) % tris.Length; 188 CreateEdge(tris[i], tris[n]); 189 } 190 } 191 192 public JobHandle TriangulateJob(ITriangulator triangulator, SpriteJobData spriteData) 193 { 194 Debug.Assert(spriteMeshData != null); 195 Debug.Assert(triangulator != null); 196 197 FillMeshDataContainers(out m_VerticesTemp, out m_EdgesTemp, out var weightData, out var hasWeightData); 198 return triangulator.ScheduleTriangulate(in m_VerticesTemp, in m_EdgesTemp, ref spriteData.vertices, ref spriteData.indices, ref spriteData.edges, ref spriteData.result); 199 } 200 201 public void Triangulate(ITriangulator triangulator) 202 { 203 Debug.Assert(spriteMeshData != null); 204 Debug.Assert(triangulator != null); 205 206 FillMeshDataContainers(out m_VerticesTemp, out m_EdgesTemp, out var weightData, out var hasWeightData); 207 triangulator.Triangulate(ref m_EdgesTemp, ref m_VerticesTemp, out var indices); 208 209 if (m_VerticesTemp.Length == 0 || indices.Length == 0) 210 { 211 spriteMeshData.Clear(); 212 CreateQuad(); 213 214 FillMeshDataContainers(out m_VerticesTemp, out m_EdgesTemp, out weightData, out hasWeightData); 215 triangulator.Triangulate(ref m_EdgesTemp, ref m_VerticesTemp, out indices); 216 } 217 218 spriteMeshData.Clear(); 219 spriteMeshData.SetIndices(indices); 220 spriteMeshData.SetEdges(m_EdgesTemp); 221 222 var hasNewVertices = m_VerticesTemp.Length != weightData.Length; 223 for (var i = 0; i < m_VerticesTemp.Length; ++i) 224 { 225 var boneWeight = default(BoneWeight); 226 if (!hasNewVertices) 227 boneWeight = weightData[i].ToBoneWeight(true); 228 spriteMeshData.AddVertex(m_VerticesTemp[i], boneWeight); 229 } 230 231 if (hasNewVertices && hasWeightData) 232 CalculateWeights(new BoundedBiharmonicWeightsGenerator(), null, 0.01f); 233 } 234 235 void FillMeshDataContainers(out float2[] vertices, out int2[] edges, out EditableBoneWeight[] weightData, out bool hasWeightData) 236 { 237 edges = spriteMeshData.edges; 238 vertices = EditorUtilities.ToFloat2(spriteMeshData.vertices); 239 240 weightData = new EditableBoneWeight[spriteMeshData.vertexWeights.Length]; 241 Array.Copy(spriteMeshData.vertexWeights, weightData, weightData.Length); 242 243 hasWeightData = false; 244 if (weightData.Length > 0 && weightData[0] != default) 245 hasWeightData = true; 246 } 247 248 public JobHandle Subdivide(ITriangulator triangulator, SpriteJobData spriteData, float largestAreaFactor, float areaThreshold) 249 { 250 Debug.Assert(spriteMeshData != null); 251 Debug.Assert(triangulator != null); 252 253 m_EdgesTemp = spriteMeshData.edges; 254 m_VerticesTemp = EditorUtilities.ToFloat2(spriteMeshData.vertices); 255 256 try 257 { 258 triangulator.Tessellate(0f, 0f, 0f, largestAreaFactor, areaThreshold, 100, ref m_VerticesTemp, ref m_EdgesTemp, out var indices); 259 260 spriteMeshData.Clear(); 261 262 for (var i = 0; i < m_VerticesTemp.Length; ++i) 263 spriteMeshData.AddVertex(m_VerticesTemp[i], default(BoneWeight)); 264 265 spriteMeshData.SetIndices(indices); 266 spriteMeshData.SetEdges(m_EdgesTemp); 267 } 268 catch (Exception) { } 269 270 return default(JobHandle); 271 } 272 273 public void ClearWeights(ISelection<int> selection) 274 { 275 Debug.Assert(spriteMeshData != null); 276 277 for (var i = 0; i < spriteMeshData.vertexCount; ++i) 278 if (selection == null || (selection.Count == 0 || selection.Contains(i))) 279 spriteMeshData.vertexWeights[i].SetFromBoneWeight(default(BoneWeight)); 280 } 281 282 public void OutlineFromAlpha(IOutlineGenerator outlineGenerator, ITextureDataProvider textureDataProvider, float outlineDetail, byte alphaTolerance) 283 { 284 Debug.Assert(spriteMeshData != null, "Assert failed. Expected: spriteMeshData != null. Actual: spriteMeshData == null"); 285 Debug.Assert(textureDataProvider != null, "Assert failed. Expected: textureDataProvider != null. Actual: textureDataProvider == null"); 286 Debug.Assert(textureDataProvider.texture != null, "Assert failed. Expected: textureDataProvider.texture != null. Actual: textureDataProvider.texture == null"); 287 288 int width, height; 289 textureDataProvider.GetTextureActualWidthAndHeight(out width, out height); 290 291 var scale = new Vector2(textureDataProvider.texture.width / (float)width, textureDataProvider.texture.height / (float)height); 292 var scaleInv = new Vector2(1f / scale.x, 1f / scale.y); 293 var rectOffset = spriteMeshData.frame.size * 0.5f; 294 295 var scaledRect = spriteMeshData.frame; 296 scaledRect.min = Vector2.Scale(scaledRect.min, scale); 297 scaledRect.max = Vector2.Scale(scaledRect.max, scale); 298 299 spriteMeshData.Clear(); 300 301 outlineGenerator.GenerateOutline(textureDataProvider, scaledRect, outlineDetail, alphaTolerance, false, out var paths); 302 303 var vertexIndexBase = 0; 304 305 var vertices = new List<Vector2>(spriteMeshData.vertices); 306 var edges = new List<int2>(spriteMeshData.edges); 307 for (var i = 0; i < paths.Length; ++i) 308 { 309 var numPathVertices = paths[i].Length; 310 311 for (var j = 0; j <= numPathVertices; j++) 312 { 313 if (j < numPathVertices) 314 vertices.Add(Vector2.Scale(paths[i][j], scaleInv) + rectOffset); 315 if (j > 0) 316 edges.Add(new int2(vertexIndexBase + j - 1, vertexIndexBase + j % numPathVertices)); 317 } 318 319 vertexIndexBase += numPathVertices; 320 } 321 322 var vertexWeights = new EditableBoneWeight[vertices.Count]; 323 for (var i = 0; i < vertexWeights.Length; ++i) 324 vertexWeights[i] = new EditableBoneWeight(); 325 326 spriteMeshData.SetVertices(vertices.ToArray(), vertexWeights); 327 spriteMeshData.SetEdges(edges.ToArray()); 328 } 329 330 public void NormalizeWeights(ISelection<int> selection) 331 { 332 Debug.Assert(spriteMeshData != null); 333 334 for (var i = 0; i < spriteMeshData.vertexCount; ++i) 335 if (selection == null || (selection.Count == 0 || selection.Contains(i))) 336 spriteMeshData.vertexWeights[i].Normalize(); 337 } 338 339 public JobHandle CalculateWeightsJob(IWeightsGenerator weightsGenerator, ISelection<int> selection, float filterTolerance, SpriteJobData sd) 340 { 341 Debug.Assert(spriteMeshData != null); 342 343 GetControlPoints(out var controlPoints, out var bones, out var pins); 344 345 var vertices = EditorUtilities.ToFloat2(spriteMeshData.vertices); 346 var indices = spriteMeshData.indices; 347 var edges = spriteMeshData.edges; 348 349 return weightsGenerator.CalculateJob(spriteMeshData.spriteName, in vertices, in indices, in edges, in controlPoints, in bones, in pins, sd); 350 } 351 352 public void CalculateWeights(IWeightsGenerator weightsGenerator, ISelection<int> selection, float filterTolerance) 353 { 354 Debug.Assert(spriteMeshData != null); 355 356 GetControlPoints(out var controlPoints, out var bones, out var pins); 357 358 var vertices = EditorUtilities.ToFloat2(spriteMeshData.vertices); 359 var indices = spriteMeshData.indices; 360 var edges = spriteMeshData.edges; 361 362 var boneWeights = weightsGenerator.Calculate(spriteMeshData.spriteName, in vertices, in indices, in edges, in controlPoints, in bones, in pins); 363 364 Debug.Assert(boneWeights.Length == spriteMeshData.vertexCount); 365 366 for (var i = 0; i < spriteMeshData.vertexCount; ++i) 367 { 368 if (selection == null || (selection.Count == 0 || selection.Contains(i))) 369 { 370 var editableBoneWeight = EditableBoneWeightUtility.CreateFromBoneWeight(boneWeights[i]); 371 372 if (filterTolerance > 0f) 373 { 374 editableBoneWeight.FilterChannels(filterTolerance); 375 editableBoneWeight.Normalize(); 376 } 377 378 spriteMeshData.vertexWeights[i] = editableBoneWeight; 379 } 380 } 381 } 382 383 public void CalculateWeightsSafe(IWeightsGenerator weightsGenerator, ISelection<int> selection, float filterTolerance) 384 { 385 var tempSelection = new IndexedSelection(); 386 var vertexSelector = new GenericVertexSelector(); 387 388 vertexSelector.spriteMeshData = spriteMeshData; 389 vertexSelector.selection = tempSelection; 390 vertexSelector.SelectionCallback = (int i) => 391 { 392 return spriteMeshData.vertexWeights[i].Sum() == 0f && (selection == null || selection.Count == 0 || selection.Contains(i)); 393 }; 394 vertexSelector.Select(); 395 396 if (tempSelection.Count > 0) 397 CalculateWeights(weightsGenerator, tempSelection, filterTolerance); 398 } 399 400 public void SmoothWeights(int iterations, ISelection<int> selection) 401 { 402 var boneWeights = new BoneWeight[spriteMeshData.vertexCount]; 403 404 for (var i = 0; i < spriteMeshData.vertexCount; i++) 405 boneWeights[i] = spriteMeshData.vertexWeights[i].ToBoneWeight(false); 406 407 SmoothingUtility.SmoothWeights(boneWeights, spriteMeshData.indices, spriteMeshData.boneCount, iterations, out var smoothedWeights); 408 409 for (var i = 0; i < spriteMeshData.vertexCount; i++) 410 if (selection == null || (selection.Count == 0 || selection.Contains(i))) 411 spriteMeshData.vertexWeights[i].SetFromBoneWeight(smoothedWeights[i]); 412 } 413 414 public bool FindTriangle(Vector2 point, out Vector3Int indices, out Vector3 barycentricCoords) 415 { 416 Debug.Assert(spriteMeshData != null); 417 418 indices = Vector3Int.zero; 419 barycentricCoords = Vector3.zero; 420 421 if (spriteMeshData.indices.Length < 3) 422 return false; 423 424 var triangleCount = spriteMeshData.indices.Length / 3; 425 426 for (var i = 0; i < triangleCount; ++i) 427 { 428 indices.x = spriteMeshData.indices[i * 3]; 429 indices.y = spriteMeshData.indices[i * 3 + 1]; 430 indices.z = spriteMeshData.indices[i * 3 + 2]; 431 432 MathUtility.Barycentric( 433 point, 434 spriteMeshData.vertices[indices.x], 435 spriteMeshData.vertices[indices.y], 436 spriteMeshData.vertices[indices.z], 437 out barycentricCoords); 438 439 if (barycentricCoords.x >= 0f && barycentricCoords.y >= 0f && barycentricCoords.z >= 0f) 440 return true; 441 } 442 443 return false; 444 } 445 446 List<float> m_VertexOrderList = new List<float>(1000); 447 List<WeightedTriangle> m_WeightedTriangles = new List<WeightedTriangle>(1000); 448 449 public void SortTrianglesByDepth() 450 { 451 Debug.Assert(spriteMeshData != null); 452 453 if (spriteMeshData.boneCount == 0) 454 return; 455 456 m_VertexOrderList.Clear(); 457 m_WeightedTriangles.Clear(); 458 459 for (var i = 0; i < spriteMeshData.vertexCount; i++) 460 { 461 var vertexOrder = 0f; 462 var boneWeight = spriteMeshData.vertexWeights[i]; 463 464 for (var j = 0; j < boneWeight.Count; ++j) 465 vertexOrder += spriteMeshData.GetBoneDepth(boneWeight[j].boneIndex) * boneWeight[j].weight; 466 467 m_VertexOrderList.Add(vertexOrder); 468 } 469 470 for (var i = 0; i < spriteMeshData.indices.Length; i += 3) 471 { 472 var p1 = spriteMeshData.indices[i]; 473 var p2 = spriteMeshData.indices[i + 1]; 474 var p3 = spriteMeshData.indices[i + 2]; 475 var weight = (m_VertexOrderList[p1] + m_VertexOrderList[p2] + m_VertexOrderList[p3]) / 3f; 476 477 m_WeightedTriangles.Add(new WeightedTriangle() { p1 = p1, p2 = p2, p3 = p3, weight = weight }); 478 } 479 480 m_WeightedTriangles.Sort(); 481 482 var newIndices = new int[m_WeightedTriangles.Count * 3]; 483 for (var i = 0; i < m_WeightedTriangles.Count; ++i) 484 { 485 var triangle = m_WeightedTriangles[i]; 486 var indexCount = i * 3; 487 newIndices[indexCount] = triangle.p1; 488 newIndices[indexCount + 1] = triangle.p2; 489 newIndices[indexCount + 2] = triangle.p3; 490 } 491 492 spriteMeshData.SetIndices(newIndices); 493 } 494 495 public void GetMultiEditChannelData(ISelection<int> selection, int channel, 496 out bool enabled, out int boneIndex, out float weight, 497 out bool isEnabledMixed, out bool isBoneIndexMixed, out bool isWeightMixed) 498 { 499 Debug.Assert(spriteMeshData != null); 500 501 if (selection == null) 502 throw new ArgumentNullException("selection is null"); 503 504 var first = true; 505 enabled = false; 506 boneIndex = -1; 507 weight = 0f; 508 isEnabledMixed = false; 509 isBoneIndexMixed = false; 510 isWeightMixed = false; 511 512 var indices = selection.elements; 513 514 foreach (var i in indices) 515 { 516 var editableBoneWeight = spriteMeshData.vertexWeights[i]; 517 518 if (first) 519 { 520 enabled = editableBoneWeight[channel].enabled; 521 boneIndex = editableBoneWeight[channel].boneIndex; 522 weight = editableBoneWeight[channel].weight; 523 524 first = false; 525 } 526 else 527 { 528 if (enabled != editableBoneWeight[channel].enabled) 529 { 530 isEnabledMixed = true; 531 enabled = false; 532 } 533 534 if (boneIndex != editableBoneWeight[channel].boneIndex) 535 { 536 isBoneIndexMixed = true; 537 boneIndex = -1; 538 } 539 540 if (Mathf.Abs(weight - editableBoneWeight[channel].weight) > Mathf.Epsilon) 541 { 542 isWeightMixed = true; 543 weight = 0f; 544 } 545 } 546 } 547 } 548 549 public void SetMultiEditChannelData(ISelection<int> selection, int channel, 550 bool oldEnabled, bool newEnabled, int oldBoneIndex, int newBoneIndex, float oldWeight, float newWeight) 551 { 552 Debug.Assert(spriteMeshData != null); 553 554 if (selection == null) 555 throw new ArgumentNullException("selection is null"); 556 557 var channelEnabledChanged = oldEnabled != newEnabled; 558 var boneIndexChanged = oldBoneIndex != newBoneIndex; 559 var weightChanged = Mathf.Abs(oldWeight - newWeight) > Mathf.Epsilon; 560 561 var indices = selection.elements; 562 563 foreach (var i in indices) 564 { 565 var editableBoneWeight = spriteMeshData.vertexWeights[i]; 566 567 if (channelEnabledChanged) 568 editableBoneWeight[channel].enabled = newEnabled; 569 570 if (boneIndexChanged) 571 editableBoneWeight[channel].boneIndex = newBoneIndex; 572 573 if (weightChanged) 574 editableBoneWeight[channel].weight = newWeight; 575 576 if (channelEnabledChanged || weightChanged) 577 editableBoneWeight.CompensateOtherChannels(channel); 578 } 579 } 580 581 public void GetControlPoints(out float2[] points, out int2[] edges, out int[] pins) 582 { 583 Debug.Assert(spriteMeshData != null); 584 585 points = null; 586 edges = null; 587 588 var pointList = new List<Vector2>(); 589 var edgeList = new List<int2>(); 590 var pinList = new List<int>(); 591 var bones = new List<SpriteBoneData>(spriteMeshData.boneCount); 592 593 for (var i = 0; i < spriteMeshData.boneCount; ++i) 594 bones.Add(spriteMeshData.GetBoneData(i)); 595 596 foreach (var bone in bones) 597 { 598 var length = (bone.endPosition - bone.position).magnitude; 599 600 if (length > 0f) 601 { 602 var index1 = FindPoint(pointList, bone.position, 0.01f); 603 var index2 = FindPoint(pointList, bone.endPosition, 0.01f); 604 605 if (index1 == -1) 606 { 607 pointList.Add(bone.position); 608 index1 = pointList.Count - 1; 609 } 610 611 if (index2 == -1) 612 { 613 pointList.Add(bone.endPosition); 614 index2 = pointList.Count - 1; 615 } 616 617 edgeList.Add(new int2(index1, index2)); 618 } 619 else if (bone.length == 0f) 620 { 621 pointList.Add(bone.position); 622 pinList.Add(pointList.Count - 1); 623 } 624 } 625 626 points = new float2[pointList.Count]; 627 for (var i = 0; i < pointList.Count; ++i) 628 points[i] = pointList[i]; 629 630 edges = edgeList.ToArray(); 631 pins = pinList.ToArray(); 632 } 633 634 static int FindPoint(IReadOnlyList<Vector2> points, Vector2 point, float distanceTolerance) 635 { 636 var sqrTolerance = distanceTolerance * distanceTolerance; 637 for (var i = 0; i < points.Count; ++i) 638 { 639 if ((points[i] - point).sqrMagnitude <= sqrTolerance) 640 return i; 641 } 642 643 return -1; 644 } 645 646 public void SmoothFill() 647 { 648 var tempSelection = new IndexedSelection(); 649 var vertexSelector = new GenericVertexSelector(); 650 var currentWeightSum = 0f; 651 var prevWeightSum = 0f; 652 653 vertexSelector.spriteMeshData = spriteMeshData; 654 vertexSelector.selection = tempSelection; 655 vertexSelector.SelectionCallback = (int i) => 656 { 657 var sum = spriteMeshData.vertexWeights[i].Sum(); 658 currentWeightSum += sum; 659 return sum < 0.99f; 660 }; 661 662 do 663 { 664 prevWeightSum = currentWeightSum; 665 currentWeightSum = 0f; 666 vertexSelector.Select(); 667 668 if (tempSelection.Count > 0) 669 SmoothWeights(1, tempSelection); 670 } while (currentWeightSum - prevWeightSum > 0.001f); 671 672 if (tempSelection.Count > 0) 673 NormalizeWeights(tempSelection); 674 } 675 } 676}