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

feat: add warnings for activeness animation of source Renderers #675

Merged
merged 12 commits into from
Nov 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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