Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remake object mapping system #137

Merged
merged 46 commits into from
May 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
a9b7f80
feat: initial commit for ObjectMappingBuilder
anatawa12 May 6, 2023
6c73d93
chore: allow multiple children
anatawa12 May 6, 2023
0244c7b
feat(ObjectMappingBuilder): support for moving component
anatawa12 May 6, 2023
cf94df1
chore(Utils.RelativePath): support for get full path
anatawa12 May 6, 2023
8c7b579
feat(ObjectMappingBuilder): support removing components or gameobjects
anatawa12 May 6, 2023
b6230a2
chore: initial migration to ObjectMappingBuilder
anatawa12 May 6, 2023
d74236a
chore: save component instance id
anatawa12 May 7, 2023
8bca8e1
chore(ObjectMappingBuilder): support for property move/deletion
anatawa12 May 7, 2023
32add8d
chore: remove Obsolete annotation on EditSkinnedMeshProcessor
anatawa12 May 7, 2023
72bdea6
chore: record move property on FreezeBlendShapeProcessor
anatawa12 May 7, 2023
ba5f994
feat(MeshInfo2): hold source Renderer in MeshInfo2
anatawa12 May 7, 2023
bd9d81b
chore: record BlendShape index changes in MergeSkinnedMeshProcessor
anatawa12 May 7, 2023
e9880b0
chore: record move object in MakeChildrenProcessor
anatawa12 May 7, 2023
3995c1a
chore: record object movements and deletion in MergeBoneProcessor
anatawa12 May 7, 2023
b1e260c
chore: record GameObject movements in MergePhysBoneProcessor
anatawa12 May 7, 2023
97dd04a
chore: same GameObject path based on relative path instead of absolute
anatawa12 May 7, 2023
2fb8726
fix: recording in DeleteGameObjectProcessor
anatawa12 May 7, 2023
c22b7a8
feat: initial commit for ObjectMapping
anatawa12 May 8, 2023
1463608
feat: add ComponentMapping in ObjectMapping
anatawa12 May 8, 2023
63d33e6
chore: add InstanceIdToComponent
anatawa12 May 8, 2023
a50247a
fix: never updated: OriginalProperties
anatawa12 May 8, 2023
7bf99df
fix: error if component is removed
anatawa12 May 8, 2023
e614abc
fix: error if GameObject is removed
anatawa12 May 8, 2023
f67a30f
chore: reimplement ApplyObjectMapping with ObjectMapper
anatawa12 May 8, 2023
79c3567
chore: move MapPath to ObjectMapping
anatawa12 May 8, 2023
40143b4
chore: move FindSubProps to Utils.cs
anatawa12 May 8, 2023
61189dc
chore: add test for Utils.FindSubProps
anatawa12 May 8, 2023
bce7633
chore: add one more test for Utils.FindSubProps
anatawa12 May 8, 2023
2e73c9b
fix: error with property deletion
anatawa12 May 8, 2023
c55c1b7
test: initial test for ObjectMapping
anatawa12 May 8, 2023
bbec02d
chore: generalize FindSubProps
anatawa12 May 8, 2023
8c3c5f3
fix: bad test
anatawa12 May 8, 2023
7cc8107
fix: bad behavior
anatawa12 May 8, 2023
715986f
test: add test for RecordRemoveGameObject
anatawa12 May 8, 2023
ac796c5
test: add test for RecordMoveComponent
anatawa12 May 8, 2023
b25f96b
test: add test for RecordRemoveComponent
anatawa12 May 8, 2023
dcc4243
test: add test for RecordMoveProperty
anatawa12 May 8, 2023
09805b6
test: add test for RecordRemoveProperty
anatawa12 May 8, 2023
c8eff4f
test: add test for complex combination of MoveProperty and Component
anatawa12 May 8, 2023
1548a1c
fix: component operation should affect to all values
anatawa12 May 8, 2023
d4e5984
test: add test for complex combination of MoveProperty and GameObject
anatawa12 May 8, 2023
fc2d6e8
docs(changelog): add Improved & reimplemented Animation (re)generatio…
anatawa12 May 8, 2023
4ec31be
chore: use struct/class instead of tuples
anatawa12 May 8, 2023
09f6f84
chore: add mapping for blendShape index fix
anatawa12 May 8, 2023
68edf67
chore: register components to ObjectMapping at first
anatawa12 May 9, 2023
ab8f1e5
Merge branch 'master' into remake-object-mapping-system
anatawa12 May 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG-PRERELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ The format is based on [Keep a Changelog].
- This is based on Modular Avatar's Error Reporting Window. thanks `@bdunderscore`

### Changed
- Improved & reimplemented Animation (re)generation system `#137`
- This is completely internal changes. Should not break your project
- In previous implementation, animations for GameObjects moved by MergeBone, MergePhysBone or else doesn't work well
- This reimplementation should fix this problem

### Deprecated

Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ The format is based on [Keep a Changelog].
- This is based on Modular Avatar's Error Reporting Window. thanks `@bdunderscore`

### Changed
- Improved & reimplemented Animation (re)generation system `#137`
- This is completely internal changes. Should not break your project
- In previous implementation, animations for GameObjects moved by MergeBone, MergePhysBone or else doesn't work well
- This reimplementation should fix this problem

### Deprecated

Expand Down
457 changes: 457 additions & 0 deletions Editor/ObjectMapping.cs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Editor/ObjectMapping.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion Editor/OptimizerSession.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Anatawa12.AvatarOptimizer
{
Expand All @@ -12,6 +14,7 @@ internal class OptimizerSession
private readonly List<Object> _toDestroy = new List<Object>();
private readonly HashSet<Object> _added = new HashSet<Object>();
private readonly DummyObject _assetFileObject;
public ObjectMappingBuilder MappingBuilder { get; }

public OptimizerSession(GameObject rootObject, bool addToAsset)
{
Expand All @@ -24,10 +27,11 @@ public OptimizerSession(GameObject rootObject, bool addToAsset)
{
_assetFileObject = null;
}

MappingBuilder = new ObjectMappingBuilder(rootObject);
}

public void AddObjectMapping<T>(T oldValue, T newValue) where T : Object => _mapping[oldValue] = newValue;
internal Dictionary<Object, Object> GetMapping() => _mapping;

public void Destroy(Object merge) => _toDestroy.Add(merge);
internal List<Object> GetObjectsToDestroy() => _toDestroy;
Expand Down Expand Up @@ -65,5 +69,11 @@ public void MarkDirtyAll()
foreach (var o in _added)
EditorUtility.SetDirty(o);
}

public string RelativePath(Transform child)
{
return Utils.RelativePath(_rootObject.transform, child) ??
throw new ArgumentException("child is not child of rootObject", nameof(child));
}
}
}
55 changes: 20 additions & 35 deletions Editor/Processors/ApplyObjectMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using UnityEngine.Assertions;
using Object = UnityEngine.Object;

namespace Anatawa12.AvatarOptimizer.Processors
Expand All @@ -14,8 +13,7 @@ internal class ApplyObjectMapping
{
public void Apply(OptimizerSession session)
{
var mapping = session.GetMapping();
mapping.FlattenMapping();
var mapping = session.MappingBuilder.BuildObjectMapping();

// replace all objects
foreach (var component in session.GetComponents<Component>())
Expand All @@ -27,13 +25,15 @@ public void Apply(OptimizerSession session)
{
if (p.propertyType == SerializedPropertyType.ObjectReference)
{
if (p.objectReferenceValue != null)
if (mapping.TryGetValue(p.objectReferenceValue, out var mapped))
p.objectReferenceValue = mapped;
if (mapping.InstanceIdToComponent.TryGetValue(p.objectReferenceInstanceIDValue,
out var mappedComponent))
p.objectReferenceValue = mappedComponent.component;

if (p.objectReferenceValue is AnimatorController controller)
{
if (mapper == null)
mapper = new AnimatorControllerMapper(mapping, component.transform, session);
mapper = new AnimatorControllerMapper(mapping,
session.RelativePath(component.transform), session);

// ReSharper disable once AccessToModifiedClosure
var mapped = BuildReport.ReportingObject(controller,
Expand All @@ -51,26 +51,17 @@ public void Apply(OptimizerSession session)

internal class AnimatorControllerMapper
{
private readonly Dictionary<(string, Type), string> _mapping = new Dictionary<(string, Type), string>();
private readonly ObjectMapping _mapping;
private readonly Dictionary<Object, Object> _cache = new Dictionary<Object, Object>();
private readonly OptimizerSession _session;
private readonly string _rootPath;
private bool _mapped = false;

public AnimatorControllerMapper(Dictionary<Object, Object> mapping, Transform root, OptimizerSession session)
public AnimatorControllerMapper(ObjectMapping mapping, string rootPath, OptimizerSession session)
{
_session = session;
foreach (var kvp in mapping)
{
if (!(kvp.Key is Component key)) continue;
if (kvp.Value == null) continue;
Assert.AreEqual(key.GetType(), kvp.Value.GetType());
var value = (Component) kvp.Value;
var relativeKey = Utils.RelativePath(root, key.transform);
if (relativeKey == null) continue;
var relativeValue = Utils.RelativePath(root, value.transform);
if (relativeValue == null) continue;
_mapping[(relativeKey, key.GetType())] = relativeValue;
}
_mapping = mapping;
_rootPath = rootPath;
}

public AnimatorController MapAnimatorController(AnimatorController controller)
Expand Down Expand Up @@ -115,18 +106,20 @@ private Object CustomClone(Object o)

foreach (var binding in AnimationUtility.GetCurveBindings(clip))
{
var newBinding = binding;
newBinding.path = MapPath(binding.path, binding.type);
var newBinding = _mapping.MapPath(_rootPath, binding);
_mapped |= newBinding != binding;
if (newBinding.type == null) continue;
newClip.SetCurve(newBinding.path, newBinding.type, newBinding.propertyName,
AnimationUtility.GetEditorCurve(clip, binding));
}

foreach (var objBinding in AnimationUtility.GetObjectReferenceCurveBindings(clip))
foreach (var binding in AnimationUtility.GetObjectReferenceCurveBindings(clip))
{
var newBinding = objBinding;
newBinding.path = MapPath(objBinding.path, objBinding.type);
var newBinding = _mapping.MapPath(_rootPath, binding);
_mapped |= newBinding != binding;
if (newBinding.type == null) continue;
AnimationUtility.SetObjectReferenceCurve(newClip, newBinding,
AnimationUtility.GetObjectReferenceCurve(clip, objBinding));
AnimationUtility.GetObjectReferenceCurve(clip, binding));
}

newClip.wrapMode = clip.wrapMode;
Expand All @@ -143,14 +136,6 @@ private Object CustomClone(Object o)
}
}

private string MapPath(string bindingPath, Type bindingType)
{
if (!_mapping.TryGetValue((bindingPath, bindingType), out var newPath))
return bindingPath;
_mapped = true;
return newPath;
}

// https://github.com/bdunderscore/modular-avatar/blob/db49e2e210bc070671af963ff89df853ae4514a5/Packages/nadena.dev.modular-avatar/Editor/AnimatorMerger.cs#LL242-L340C10
// Originally under MIT License
// Copyright (c) 2022 bd_
Expand Down
18 changes: 2 additions & 16 deletions Editor/Processors/DeleteGameObjectProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,9 @@ public void Process(OptimizerSession session)
{
BuildReport.ReportingObjects(session.GetComponents<DeleteGameObject>(), mergePhysBone =>
{
void Destroy(Object obj)
{
session.Destroy(obj);
session.AddObjectMapping(obj, null);
}

session.MappingBuilder.RecordRemoveGameObject(mergePhysBone.gameObject);
mergePhysBone.transform.parent = null;
Destroy(mergePhysBone.gameObject);
foreach (var component in mergePhysBone.GetComponents<Component>())
Destroy(component);
mergePhysBone.transform.WalkChildren(x =>
{
Destroy(x.gameObject);
foreach (var component in x.GetComponents<Component>())
Destroy(component);
return true;
});
session.Destroy(mergePhysBone.gameObject);
});
}
}
Expand Down
9 changes: 6 additions & 3 deletions Editor/Processors/MakeChildrenProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Anatawa12.AvatarOptimizer.ErrorReporting;
using System.Linq;

namespace Anatawa12.AvatarOptimizer.Processors
{
Expand All @@ -8,9 +9,11 @@ public void Process(OptimizerSession session)
{
BuildReport.ReportingObjects(session.GetComponents<MakeChildren>(), makeChildren =>
{
foreach (var makeChildrenChild in makeChildren.children.GetAsSet())
if (makeChildrenChild)
makeChildrenChild.parent = makeChildren.transform;
foreach (var makeChildrenChild in makeChildren.children.GetAsSet().Where(x => x))
{
session.MappingBuilder.RecordMoveObject(makeChildrenChild.gameObject, makeChildren.gameObject);
makeChildrenChild.parent = makeChildren.transform;
}
});
}
}
Expand Down
4 changes: 4 additions & 0 deletions Editor/Processors/MergeBoneProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,13 @@ public void Process(OptimizerSession session)
var mapping = pair.Key;
var mapped = pair.Value;
foreach (var child in mapping.DirectChildrenEnumerable())
{
session.MappingBuilder.RecordMoveObject(child.gameObject, mapped.gameObject);
child.parent = mapped;
}

session.Destroy(mapping.gameObject);
session.MappingBuilder.RecordRemoveGameObject(mapping.gameObject);
}
}

Expand Down
14 changes: 11 additions & 3 deletions Editor/Processors/MergePhysBoneProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ internal static void DoMerge(MergePhysBone merge, OptimizerSession session)
return; // error reported by validator

foreach (var physBone in sourceComponents)
physBone.GetTarget().parent = root;
{
var pbTarget = physBone.GetTarget();
session.MappingBuilder.RecordMoveObject(pbTarget.gameObject, root.gameObject);
pbTarget.parent = root;
}
}
else
{
Expand All @@ -58,10 +62,14 @@ internal static void DoMerge(MergePhysBone merge, OptimizerSession session)
}
else
{
root = Utils.NewGameObject("PhysBoneRoot", pb.GetTarget().parent).transform;
root = Utils.NewGameObject($"PhysBoneRoot-{Guid.NewGuid()}", pb.GetTarget().parent).transform;

foreach (var physBone in sourceComponents)
physBone.GetTarget().parent = root;
{
var pbTarget = physBone.GetTarget();
session.MappingBuilder.RecordMoveObject(pbTarget.gameObject, root.gameObject);
pbTarget.parent = root;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ internal abstract class EditSkinnedMeshProcessor<TComponent> : IEditSkinnedMeshP
public abstract int ProcessOrder { get; }
public IEnumerable<SkinnedMeshRenderer> Dependencies => Array.Empty<SkinnedMeshRenderer>();
protected TComponent Component { get; }
[Obsolete]
public SkinnedMeshRenderer Target { get; }

EditSkinnedMeshComponent IEditSkinnedMeshProcessor.Component => Component;
Expand Down
14 changes: 14 additions & 0 deletions Editor/Processors/SkinnedMeshes/FreezeBlendShapeProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,22 @@ public override void Process(OptimizerSession session, MeshInfo2 target, MeshInf
{
int srcI = 0, dstI = 0;
for (; srcI < target.BlendShapes.Count; srcI++)
{
if (!freezes[srcI])
{
// for keep prop: move the BlendShape index. name is not changed.
session.MappingBuilder.RecordMoveProperty(Target,
VProp.BlendShapeIndex(srcI),
VProp.BlendShapeIndex(dstI));
target.BlendShapes[dstI++] = target.BlendShapes[srcI];
}
else
{
// for frozen prop: remove that BlendShape
session.MappingBuilder.RecordRemoveProperty(Target, VProp.BlendShapeIndex(srcI));
session.MappingBuilder.RecordRemoveProperty(Target, $"blendShape.{target.BlendShapes[srcI].name}");
}
}

target.BlendShapes.RemoveRange(dstI, target.BlendShapes.Count - dstI);
}
Expand Down
16 changes: 13 additions & 3 deletions Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,19 @@ TexCoordStatus TexCoordStatusMax(TexCoordStatus x, TexCoordStatus y) =>
target.SubMeshes[subMeshIndexMap[i][j]].Triangles.AddRange(meshInfo.SubMeshes[j].Triangles);

// add blend shape if not defined by name
foreach (var (name, weight) in meshInfo.BlendShapes)
if (target.BlendShapes.FindIndex(x => x.name == name) == -1)
for (var sourceI = 0; sourceI < meshInfo.BlendShapes.Count; sourceI++)
{
var (name, weight) = meshInfo.BlendShapes[sourceI];
var newIndex = target.BlendShapes.FindIndex(x => x.name == name);
if (newIndex == -1)
{
newIndex = target.BlendShapes.Count - 1;
target.BlendShapes.Add((name, weight));
}

session.MappingBuilder.RecordMoveProperty(meshInfo.SourceRenderer,
VProp.BlendShapeIndex(sourceI), VProp.BlendShapeIndex(newIndex));
}

target.Bones.AddRange(meshInfo.Bones);

Expand All @@ -62,7 +72,7 @@ TexCoordStatus TexCoordStatusMax(TexCoordStatus x, TexCoordStatus y) =>

foreach (var renderer in Component.renderersSet.GetAsSet())
{
session.AddObjectMapping(renderer, Target);
session.MappingBuilder.RecordMoveComponent(renderer, Component.gameObject);
session.Destroy(renderer);

// process removeEmptyRendererObject
Expand Down
3 changes: 3 additions & 0 deletions Editor/Processors/SkinnedMeshes/MeshInfo2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace Anatawa12.AvatarOptimizer.Processors.SkinnedMeshes
{
internal class MeshInfo2
{
public readonly Renderer SourceRenderer;
public Bounds Bounds;
public readonly List<Vertex> Vertices = new List<Vertex>(0);

Expand All @@ -29,6 +30,7 @@ internal class MeshInfo2

public MeshInfo2(SkinnedMeshRenderer renderer)
{
SourceRenderer = renderer;
var mesh = renderer.sharedMesh ? renderer.sharedMesh : new Mesh();
ReadSkinnedMesh(mesh);

Expand All @@ -52,6 +54,7 @@ public MeshInfo2(SkinnedMeshRenderer renderer)

public MeshInfo2(MeshRenderer renderer)
{
SourceRenderer = renderer;
var mesh = renderer.GetComponent<MeshFilter>().sharedMesh;
ReadStaticMesh(mesh);

Expand Down
Loading