Skip to content

Commit

Permalink
com.unity.2d.animation@9.0.1
Browse files Browse the repository at this point in the history
## [9.0.1] - 2022-10-11
### Fixed
- Fixed a case where pasting bones in the Skinning Editor would move bones rather than copy them. (case DANB-179)
- Fixed an issue where selecting bones in the Skinning Editor after removing any bone in the skeleton will throw an exception. (case DANB-186)
- Fixed a case where setting IKManager2D's or Solver2D's weight to '0' doesn't update solver's effector position. (case DANB-191)
- Fixed an issue where undo the addition of a Sprite Skin component would crash the editor. (DANB-201)
- Fixed a case where new bones are not selected after pasting them in the Skinning Editor and an exception is thrown. (DANB-209)
- Fixed a case where the auto weight generation would associate incorrect bones to vertices. (case DANB-22)
- Improved the Auto Geometry generation speed.
- Fixed a case where a .psd/.psb with a Main Skeleton assigned would generate incorrect bind poses. (Case DANB-225)
- Fixed IK Manager 2D's inspector slow downs. (case DANB-215)
- Fixed an issue where the Sprite Skin editor would throw an exception if Sprite Renderer doesn't have a Sprite assigned to it.

### Changed
- Expand and frame on bone selection.
  • Loading branch information
Unity Technologies committed Oct 11, 2022
1 parent df690dc commit be82b4c
Show file tree
Hide file tree
Showing 22 changed files with 1,150 additions and 559 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## [9.0.1] - 2022-10-11
### Fixed
- Fixed a case where pasting bones in the Skinning Editor would move bones rather than copy them. (case DANB-179)
- Fixed an issue where selecting bones in the Skinning Editor after removing any bone in the skeleton will throw an exception. (case DANB-186)
- Fixed a case where setting IKManager2D's or Solver2D's weight to '0' doesn't update solver's effector position. (case DANB-191)
- Fixed an issue where undo the addition of a Sprite Skin component would crash the editor. (DANB-201)
- Fixed a case where new bones are not selected after pasting them in the Skinning Editor and an exception is thrown. (DANB-209)
- Fixed a case where the auto weight generation would associate incorrect bones to vertices. (case DANB-22)
- Improved the Auto Geometry generation speed.
- Fixed a case where a .psd/.psb with a Main Skeleton assigned would generate incorrect bind poses. (Case DANB-225)
- Fixed IK Manager 2D's inspector slow downs. (case DANB-215)
- Fixed an issue where the Sprite Skin editor would throw an exception if Sprite Renderer doesn't have a Sprite assigned to it.

### Changed
- Expand and frame on bone selection.

## [9.0.0] - 2022-08-03
### Added
- Added bone weight index validation in SpriteSkin's validate method, to ensure valid data before continuing with deformation.
Expand Down
2 changes: 1 addition & 1 deletion Editor/EditorUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace UnityEditor.U2D.Animation
internal static class EditorUtilities
{
/// <summary>
/// Checks if element exists in array independent of the order of X & Y.
/// Checks if element exists in array independent of the order of X and Y.
/// </summary>
public static bool ContainsAny(this int2[] array, int2 element)
{
Expand Down
478 changes: 280 additions & 198 deletions Editor/SkinningModule/CopyTool.cs

Large diffs are not rendered by default.

218 changes: 186 additions & 32 deletions Editor/SkinningModule/GenerateGeometryTool.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using System;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEditor.U2D.Common;
using UnityEditor.U2D.Layout;
using UnityEngine;
Expand Down Expand Up @@ -55,9 +59,16 @@ private void BindElements()
void GenerateGeometryForSprites(SpriteCache[] sprites, float detail, byte alpha, float subdivide)
{
var cancelProgress = false;

using (skinningCache.UndoScope(TextContent.generateGeometry))
{

float progressMax = sprites.Length * 4; // for ProgressBar
int validSpriteCount = 0;

//
// Generate Outline
//
for (var i = 0; i < sprites.Length; ++i)
{
var sprite = sprites[i];
Expand All @@ -69,34 +80,182 @@ void GenerateGeometryForSprites(SpriteCache[] sprites, float detail, byte alpha,
Debug.Assert(mesh != null);

m_SpriteMeshDataController.spriteMeshData = mesh;

cancelProgress = EditorUtility.DisplayCancelableProgressBar(TextContent.generatingOutline, sprite.name, i / (sprites.Length * 4f));
validSpriteCount++;

cancelProgress = EditorUtility.DisplayCancelableProgressBar(TextContent.generatingOutline, sprite.name, i / progressMax);
if (cancelProgress)
break;
m_SpriteMeshDataController.OutlineFromAlpha(m_OutlineGenerator, mesh.textureDataProvider, detail / 100f, alpha);

cancelProgress = EditorUtility.DisplayCancelableProgressBar(TextContent.triangulatingGeometry, sprite.name, (i * 2) / (sprites.Length * 4f));
}

//
// Generate Base Mesh Threaded.
//
const int maxDataCount = 65536;
var spriteList = new List<SpriteJobData>();
var jobHandles = new NativeArray<JobHandle>(validSpriteCount, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
int jobCount = 0;

for (var i = 0; i < sprites.Length; ++i)
{
var sprite = sprites[i];
if (!sprite.IsVisible())
continue;

cancelProgress = EditorUtility.DisplayCancelableProgressBar(TextContent.triangulatingGeometry, sprite.name, 0.25f + (i / progressMax));
if (cancelProgress)
break;
m_SpriteMeshDataController.Triangulate(m_Triangulator);

if (subdivide > 0f)

var mesh = sprite.GetMesh();
m_SpriteMeshDataController.spriteMeshData = mesh;

SpriteJobData sd = new SpriteJobData();
sd.spriteMesh = mesh;
sd.vertices = new NativeArray<float2>(maxDataCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
sd.edges = new NativeArray<int2>(maxDataCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
sd.indices = new NativeArray<int>(maxDataCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
sd.weights = new NativeArray<BoneWeight>(maxDataCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
sd.result = new NativeArray<int4>(1, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
sd.result[0] = int4.zero;
spriteList.Add(sd);
if (m_GenerateGeometryPanel.generateWeights)
{
jobHandles[jobCount] = m_SpriteMeshDataController.TriangulateJob(m_Triangulator, sd);
}
else
{
jobHandles[jobCount] = default(JobHandle);
m_SpriteMeshDataController.Triangulate(m_Triangulator);
}
jobCount++;
}
JobHandle.CombineDependencies(jobHandles).Complete();

//
// Generate Base Mesh Fallback.
//
for (var i = 0; i < spriteList.Count; i++)
{
var sd = spriteList[i];
if (math.all(sd.result[0].xy))
{
cancelProgress = EditorUtility.DisplayCancelableProgressBar(TextContent.subdividingGeometry, sprite.name, (i * 3) / (sprites.Length * 4f));
sd.spriteMesh.Clear();

var edges = new int2[sd.result[0].z];
var indices = new int[sd.result[0].y];

for (var j = 0; j < sd.result[0].x; ++j)
sd.spriteMesh.AddVertex(sd.vertices[j], default(BoneWeight));
for (var j = 0; j < sd.result[0].y; ++j)
indices[j] = sd.indices[j];
for (var j = 0; j < sd.result[0].z; ++j)
edges[j] = sd.edges[j];

sd.spriteMesh.SetEdges(edges);
sd.spriteMesh.SetIndices(indices);
}
else
{
m_SpriteMeshDataController.spriteMeshData = sd.spriteMesh;
m_SpriteMeshDataController.Triangulate(m_Triangulator);
}
}

//
// Subdivide.
//

jobCount = 0;
if (subdivide > 0f)
{
var largestAreaFactor = subdivide != 0 ? Mathf.Lerp(0.5f, 0.05f, Math.Min(subdivide, 100f) / 100f) : subdivide;

for (var i = 0; i < sprites.Length; ++i)
{
var sprite = sprites[i];
if (!sprite.IsVisible())
continue;

cancelProgress = EditorUtility.DisplayCancelableProgressBar(TextContent.subdividingGeometry, sprite.name, 0.5f + (i / progressMax));
if (cancelProgress)
break;
var largestAreaFactor = subdivide != 0 ? Mathf.Lerp(0.5f, 0.05f, Math.Min(subdivide, 100f) / 100f) : subdivide;
m_SpriteMeshDataController.Subdivide(m_Triangulator, largestAreaFactor, 0f);
}

if (m_GenerateGeometryPanel.generateWeights)
var mesh = sprite.GetMesh();
m_SpriteMeshDataController.spriteMeshData = mesh;

var sd = spriteList[i];
sd.spriteMesh = mesh;
sd.result[0] = int4.zero;
m_SpriteMeshDataController.Subdivide(m_Triangulator, sd, largestAreaFactor, 0f);
}

}

//
// Weight.
//
jobCount = 0;
if (m_GenerateGeometryPanel.generateWeights)
{

for (var i = 0; i < sprites.Length; i++)
{
cancelProgress = EditorUtility.DisplayCancelableProgressBar(TextContent.generatingWeights, sprite.name, (i * 4) / (sprites.Length * 4f));
var sprite = sprites[i];
if (!sprite.IsVisible())
continue;

var mesh = sprite.GetMesh();
m_SpriteMeshDataController.spriteMeshData = mesh;

cancelProgress = EditorUtility.DisplayCancelableProgressBar(TextContent.generatingWeights, sprite.name, 0.75f + (i / progressMax));
if (cancelProgress)
break;

GenerateWeights(sprite);

var sd = spriteList[i];
jobHandles[jobCount] = GenerateWeights(sprite, sd);
jobCount++;
}

// Weight
JobHandle.CombineDependencies(jobHandles).Complete();

for (var i = 0; i < sprites.Length; i++)
{
var sprite = sprites[i];
if (!sprite.IsVisible())
continue;

var mesh = sprite.GetMesh();
m_SpriteMeshDataController.spriteMeshData = mesh;
var sd = spriteList[i];

for (var j = 0; j < mesh.vertexCount; ++j)
{
var editableBoneWeight = EditableBoneWeightUtility.CreateFromBoneWeight(sd.weights[j]);

if (kWeightTolerance > 0f)
{
editableBoneWeight.FilterChannels(kWeightTolerance);
editableBoneWeight.Normalize();
}

mesh.vertexWeights[j] = editableBoneWeight;
}
if (null != sprite.GetCharacterPart())
sprite.DeassociateUnusedBones();
m_SpriteMeshDataController.SortTrianglesByDepth();
}

}

for (var i = 0; i < spriteList.Count; i++)
{
var sd = spriteList[i];
sd.result.Dispose();
sd.indices.Dispose();
sd.edges.Dispose();
sd.vertices.Dispose();
sd.weights.Dispose();
}

if (!cancelProgress)
Expand All @@ -105,14 +264,14 @@ void GenerateGeometryForSprites(SpriteCache[] sprites, float detail, byte alpha,
foreach(var sprite in sprites)
skinningCache.events.meshChanged.Invoke(sprite.GetMesh());
}

EditorUtility.ClearProgressBar();
}

if(cancelProgress)
Undo.PerformUndo();
}

protected override void OnActivate()
{
base.OnActivate();
Expand Down Expand Up @@ -153,7 +312,7 @@ private void OnSelectedSpriteChanged(SpriteCache sprite)
UpdateButton();
}

private void GenerateWeights(SpriteCache sprite)
private JobHandle GenerateWeights(SpriteCache sprite, SpriteJobData sd)
{
Debug.Assert(sprite != null);

Expand All @@ -163,18 +322,12 @@ private void GenerateWeights(SpriteCache sprite)

using (new DefaultPoseScope(skinningCache.GetEffectiveSkeleton(sprite)))
{
if (NeedsAssociateBones(sprite.GetCharacterPart()))
{
using (new AssociateBonesScope(sprite))
{
GenerateWeights(mesh);
}
}
else
GenerateWeights(mesh);
sprite.AssociatePossibleBones();
return GenerateWeights(mesh, sd);
}
}

// todo: Remove. This function seems dubious. Only associate if boneCount is 0 or if boneCount 1 and first bone matches ?
private bool NeedsAssociateBones(CharacterPartCache characterPart)
{
if (characterPart == null)
Expand All @@ -186,13 +339,14 @@ private bool NeedsAssociateBones(CharacterPartCache characterPart)
(characterPart.boneCount == 1 && characterPart.GetBone(0) == skeleton.GetBone(0));
}

private void GenerateWeights(MeshCache mesh)
private JobHandle GenerateWeights(MeshCache mesh, SpriteJobData sd)
{
Debug.Assert(mesh != null);

m_SpriteMeshDataController.spriteMeshData = mesh;
m_SpriteMeshDataController.CalculateWeights(m_WeightGenerator, null, kWeightTolerance);
m_SpriteMeshDataController.SortTrianglesByDepth();
var JobHandle = m_SpriteMeshDataController.CalculateWeightsJob(m_WeightGenerator, null, kWeightTolerance, sd);

return JobHandle;
}

protected override void OnGUI()
Expand Down
28 changes: 28 additions & 0 deletions Editor/SkinningModule/IMGUI/SkeletonController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,17 @@ public static string AutoBoneName(BoneCache parent, IEnumerable<BoneCache> bones

return String.Format("{0}_{1}", inheritedName, ++nameCounter);
}

public static string AutoNameBoneCopy(string originalBoneName, IEnumerable<BoneCache> bones)
{
DissectBoneName(originalBoneName, out var inheritedName, out _);
int nameCounter = FindBiggestNameCounterForBone(inheritedName, bones);

if (inheritedName == k_DefaultRootName)
inheritedName = k_DefaultBoneName;

return String.Format("{0}_{1}", inheritedName, ++nameCounter);
}

private static int FindBiggestNameCounter(IEnumerable<BoneCache> bones)
{
Expand All @@ -598,6 +609,23 @@ private static int FindBiggestNameCounter(IEnumerable<BoneCache> bones)
}
return autoNameCounter;
}

static int FindBiggestNameCounterForBone(string boneName, IEnumerable<BoneCache> bones)
{
var autoNameCounter = 0;
foreach (var bone in bones)
{
DissectBoneName(bone.name, out var inheritedName, out var counter);
{
if (inheritedName == boneName)
{
if (counter > autoNameCounter)
autoNameCounter = counter;
}
}
}
return autoNameCounter;
}

private static void DissectBoneName(string boneName, out string inheritedName, out int counter)
{
Expand Down
8 changes: 8 additions & 0 deletions Editor/SkinningModule/SkeletonTool/SkeletonTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ protected override void OnActivate()
{
SetupSkeleton(skinningCache.GetEffectiveSkeleton(skinningCache.selectedSprite));
UpdateBoneInspector();
skinningCache.events.skeletonTopologyChanged.AddListener(SkeletonTopologyChanged);
skinningCache.events.boneSelectionChanged.AddListener(BoneSelectionChanged);
skinningCache.events.selectedSpriteChanged.AddListener(SelectedSpriteChanged);
skinningCache.events.skinningModeChanged.AddListener(SkinningModeChanged);
Expand All @@ -98,6 +99,7 @@ protected override void OnDeactivate()
{
m_SkeletonToolView.Hide();
m_SkeletonController.Reset();
skinningCache.events.skeletonTopologyChanged.RemoveListener(SkeletonTopologyChanged);
skinningCache.events.boneSelectionChanged.RemoveListener(BoneSelectionChanged);
skinningCache.events.selectedSpriteChanged.RemoveListener(SelectedSpriteChanged);
skinningCache.events.skinningModeChanged.RemoveListener(SkinningModeChanged);
Expand All @@ -107,6 +109,12 @@ protected override void OnDeactivate()
skeletonStyle = null;
}

void SkeletonTopologyChanged(SkeletonCache skeletonCache)
{
if (skeleton == skeletonCache && skeleton != null)
m_RectBoneSelector.bones = skeleton.bones;
}

void BoneDataChanged(BoneCache bone)
{
if(m_SkeletonToolView.target == bone)
Expand Down
Loading

0 comments on commit be82b4c

Please sign in to comment.