Skip to content

Commit

Permalink
Merge pull request #675 from anatawa12/warn-smr-animations
Browse files Browse the repository at this point in the history
feat: add warnings for activeness animation of source Renderers
  • Loading branch information
anatawa12 authored Nov 5, 2023
2 parents e423fff + 4c768e4 commit 5470596
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 30 deletions.
1 change: 1 addition & 0 deletions CHANGELOG-PRERELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog].
- Support for Mesh Topologies other than Triangles `#692`

### Changed
- When you're animating activeness/enablement of source renderers, warning is shown since this release `#675`

### Deprecated

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ The format is based on [Keep a Changelog].
- Improved Behaviour with multi-material multi pass rendering `#662`
- Previously, multi-material multi pass rendering are flattened.
- Since 1.6, flattened if component doesn't support that.
- When you're animating activeness/enablement of source renderers, warning is shown since this release `#675`

### Deprecated

Expand Down
4 changes: 2 additions & 2 deletions Editor/AnimatorParsers/ModificationsContainers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ public float ConstValue
}

private readonly Object[] _sources;
public Span<Object> Sources => _sources ?? Array.Empty<Object>();
public ReadOnlySpan<Object> Sources => _sources ?? Array.Empty<Object>();

private AnimationFloatProperty(PropertyState state, float constValue, params Object[] modifiers) =>
(State, _constValue, _sources) = (state, constValue, modifiers);
Expand All @@ -309,7 +309,7 @@ private static AnimationFloatProperty ConstPartially0(float value, Object[] modi
private static AnimationFloatProperty Variable0(Object[] modifiers) =>
new AnimationFloatProperty(PropertyState.Variable, float.NaN, modifiers);

private Object[] MergeSource(Span<Object> aSource, Span<Object> bSource)
private Object[] MergeSource(ReadOnlySpan<Object> aSource, ReadOnlySpan<Object> bSource)
{
var merged = new Object[aSource.Length + bSource.Length];
aSource.CopyTo(merged.AsSpan().Slice(0, aSource.Length));
Expand Down
53 changes: 38 additions & 15 deletions Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,23 +68,14 @@ public override void Process(BuildContext context, MeshInfo2 target)
{
// collect (skinned) mesh renderers who doesn't have normal
// to show the list on the error reporting
var meshes = new Renderer[meshInfos.Length];
for (var i = 0; i < skinnedMeshRenderers.Count; i++)
meshes[i] = skinnedMeshRenderers[i];
for (var i = 0; i < staticMeshRenderers.Count; i++)
meshes[i + skinnedMeshRenderers.Count] = staticMeshRenderers[i];

var meshesWithoutNormals = new List<Renderer>();
for (var i = 0; i < meshInfos.Length; i++)
{
var meshInfo2 = meshInfos[i];
if (meshInfo2.Vertices.Count != 0 && !meshInfo2.HasNormals)
meshesWithoutNormals.Add(meshes[i]);
}
// ReSharper disable once CoVariantArrayConversion
BuildReport.LogFatal("MergeSkinnedMesh:error:mix-normal-existence")
?.WithContext((object[])meshesWithoutNormals.ToArray());
?.WithContext((
from meshInfo2 in meshInfos
where meshInfo2.Vertices.Count != 0 && !meshInfo2.HasNormals
select (object)meshInfo2.SourceRenderer
).ToArray());
}

Profiler.EndSample();

Profiler.BeginSample("Merge Material Indices");
Expand Down Expand Up @@ -202,6 +193,8 @@ TexCoordStatus TexCoordStatusMax(TexCoordStatus x, TexCoordStatus y) =>

var boneTransforms = new HashSet<Transform>(target.Bones.Select(x => x.Transform));

var parents = new HashSet<Transform>(Target.transform.ParentEnumerable(context.AvatarRootTransform, includeMe: true));

Profiler.BeginSample("Postprocess Source Renderers");
foreach (var renderer in SkinnedMeshRenderers)
{
Expand All @@ -212,6 +205,9 @@ TexCoordStatus TexCoordStatusMax(TexCoordStatus x, TexCoordStatus y) =>
// property for original mesh in animation.
// This invalidation doesn't affect to m_Enabled property of merged mesh.
context.RecordRemoveProperty(renderer, "m_Enabled");

ActivenessAnimationWarning(renderer, context, parents);

context.RecordMergeComponent(renderer, Target);
var rendererGameObject = renderer.gameObject;
var toDestroy = renderer.GetComponent<RemoveZeroSizedPolygon>();
Expand All @@ -237,6 +233,7 @@ TexCoordStatus TexCoordStatusMax(TexCoordStatus x, TexCoordStatus y) =>

foreach (var renderer in StaticMeshRenderers)
{
ActivenessAnimationWarning(renderer, context, parents);
Object.DestroyImmediate(renderer.GetComponent<MeshFilter>());
Object.DestroyImmediate(renderer);
}
Expand All @@ -262,6 +259,32 @@ TexCoordStatus TexCoordStatusMax(TexCoordStatus x, TexCoordStatus y) =>
#endif
}

private void ActivenessAnimationWarning(Renderer renderer, BuildContext context, HashSet<Transform> parents)
{
ErrorLog log = null;

// Warn if the source mesh can be hidden differently than merged by animation.
{
if (context.GetAnimationComponent(renderer).TryGetFloat("m_Enabled", out var p))
{
log = log ?? BuildReport.LogWarning("MergeSkinnedMesh:warning:animation-mesh-hide")
?.WithContext(renderer);
log?.WithContext(p.Sources);
}
}
foreach (var transform in renderer.transform.ParentEnumerable(context.AvatarRootTransform, includeMe: true))
{
if (parents.Contains(transform)) break;
if (context.GetAnimationComponent(transform.gameObject).TryGetFloat("m_IsActive", out var p))
{
log = log ?? BuildReport.LogWarning("MergeSkinnedMesh:warning:animation-mesh-hide")
?.WithContext(renderer);
log?.WithContext(transform.gameObject);
log?.WithContext(p.Sources);
}
}
}

private (int[][] mapping, List<(MeshTopology topology, Material material)> materials)
CreateMergedMaterialsAndSubMeshIndexMapping(
(MeshTopology topology, Material material)[][] sourceMaterials)
Expand Down
52 changes: 44 additions & 8 deletions Editor/Utils/Utils.TransformParentEnumerable.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,74 @@
using System;
using System.Collections;
using System.Collections.Generic;
using JetBrains.Annotations;
using UnityEngine;

namespace Anatawa12.AvatarOptimizer
{
internal partial class Utils
{
public static TransformParentEnumerable ParentEnumerable(this Transform transform) =>
new TransformParentEnumerable(transform);
transform.ParentEnumerable(null);

public static TransformParentEnumerable ParentEnumerable(this Transform transform, bool includeMe) =>
transform.ParentEnumerable(null, includeMe);

// root is exclusive
public static TransformParentEnumerable ParentEnumerable(this Transform transform,
Transform root, bool includeMe = false) =>
new TransformParentEnumerable(transform, root, includeMe);

public readonly struct TransformParentEnumerable : IEnumerable<Transform>
{
private readonly Transform _transform;
private readonly Transform _root;
private readonly bool _includeMe;

public TransformParentEnumerable(Transform transform, Transform root, bool includeMe) =>
(_transform, _root, _includeMe) = (transform, root, includeMe);

public TransformParentEnumerable(Transform transform) => _transform = transform;
public Enumerator GetEnumerator() => new Enumerator(_transform);
public Enumerator GetEnumerator() => new Enumerator(_transform, _root, _includeMe);
IEnumerator<Transform> IEnumerable<Transform>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

public struct Enumerator : IEnumerator<Transform>
{
object IEnumerator.Current => Current;
public Transform Current { get; private set; }
[NotNull] public Transform Current => _current ? _current : throw new Exception("invalid state");

private readonly Transform _initial;
private readonly Transform _root;
private readonly bool _includeMe;

public Enumerator(Transform transform) => _initial = Current = transform;
private bool _beforeFirst;
private Transform _current;

public Enumerator(Transform transform, Transform root, bool includeMe)
{
_current = null;
_initial = transform;
_root = root;
_includeMe = includeMe;
_beforeFirst = true;
}

public bool MoveNext()
{
Current = Current != null ? Current.parent : null;
return Current != null;
if (_beforeFirst)
_current = _includeMe ? _initial : _initial != null ? _initial.parent : null;
else
_current = _current != null ? _current.parent : null;
_beforeFirst = false;
if (_current == _root) _current = null;
return _current != null;
}

public void Reset() => Current = _initial;
public void Reset()
{
_beforeFirst = true;
_current = null;
}

public void Dispose()
{
Expand Down
28 changes: 23 additions & 5 deletions Internal/ErrorReporter/Editor/ErrorLog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ internal Object FindByGuidAndLocalId(string guid, long localId)
{
if (!_cache.TryGetValue((guid, localId), out var obj))
{
if (GlobalObjectId.TryParse($"GlobalObjectId_V1-{1}-{guid}-{localId}-{0}", out var goid))
// 1: Imported Asset
// 3: Source Asset
foreach (var type in new [] { 1, 3 })
{
obj = GlobalObjectId.GlobalObjectIdentifierToObjectSlow(goid);
if (obj) _cache[(guid, localId)] = obj;
if (GlobalObjectId.TryParse($"GlobalObjectId_V1-{type}-{guid}-{localId}-{0}", out var goid))
{
obj = GlobalObjectId.GlobalObjectIdentifierToObjectSlow(goid);
if (obj) _cache[(guid, localId)] = obj;
}
}
}

Expand Down Expand Up @@ -200,12 +205,25 @@ public ErrorLog(ReportLevel level, string code, string[] strings)
public ErrorLog WithContext(params object[] args)
{
referencedObjects.InsertRange(0,
args.Where(o => o is Component || o is GameObject)
.Select(o => new ObjectRef(o is Component c ? c.gameObject : (GameObject)o))
args.Where(o => o is Component || o is GameObject || o is Object)
.Select(o => new ObjectRef((Object)o))
.ToList());
return this;
}

public void WithContext<T>(ReadOnlySpan<T> args)
{
foreach (var arg in args)
{
if (arg is Component c)
referencedObjects.Add(new ObjectRef(c));
else if (arg is GameObject go)
referencedObjects.Add(new ObjectRef(go));
else if (arg is Object o)
referencedObjects.Add(new ObjectRef(o));
}
}

internal ErrorLog(Exception e, string additionalStackTrace = "")
: this(ReportLevel.InternalError,
"ErrorReporter:error.internal_error",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"System.Memory.dll",
"VRCSDK3A.dll",
"VRCSDKBase.dll",
"VRCSDKBase-Editor.dll"
Expand Down
5 changes: 5 additions & 0 deletions Localization/en.po
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,11 @@ msgstr ""
msgid "MergeSkinnedMesh:warning:removeZeroSizedPolygonOnSources"
msgstr "Since Remove Zero Sized Polygons are processed later, it has no effects if it is added with the source Skinned Mesh Renderers."

msgid "MergeSkinnedMesh:warning:animation-mesh-hide"
msgstr ""
"You're merging meshes that visibility animated differently than the merged mesh."
"The animation will not work. This might not be intended, but if it's intended, ignore this warning."

# endregion

# region MergeToonLitMaterial
Expand Down
5 changes: 5 additions & 0 deletions Localization/ja.po
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,11 @@ msgstr "瞬き用のBlendShapeが削除・固定されています"
msgid "ApplyObjectMapping:VRCAvatarDescriptor:viseme BlendShape Removed"
msgstr "リップシンク用のBlendShapeが削除・固定されています"

msgid "MergeSkinnedMesh:warning:animation-mesh-hide"
msgstr ""
"統合先のメッシュとは異なるアニメーションで表示されるメッシュが統合対象に含まれているため、"
"そのアニメーションによる切り替えは機能しなくなります。意図的に行っている場合はこの警告を無視してください。"

#endregion

#region MeshInfo2
Expand Down

0 comments on commit 5470596

Please sign in to comment.