Skip to content

Commit

Permalink
Merge pull request #1276 from anatawa12/merge-skinned-mesh-animation-…
Browse files Browse the repository at this point in the history
…conflict

fix: Animation for target renderer of Merge Skinned Mesh might be overridden by animation for source renderer
  • Loading branch information
anatawa12 authored Oct 18, 2024
2 parents bdf7913 + 4834fff commit 71acd88
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG-PRERELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog].
### Removed

### Fixed
- Animation for target renderer of Merge Skinned Mesh might be overridden by animation for source renderer `#1276`

### Security

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ The format is based on [Keep a Changelog].
- Material property animation with weight 0 layer might be broken with AutoMergeSkinnedMesh `#1248` `#1253`
- Remove Mesh in Box does not work for meshes without Bones `#1256`
- NullReferenceException in `GetBlendShape` if Mesh is not specified for SkinnedMeshRenderer `#1267`
- Animation for target renderer of Merge Skinned Mesh might be overridden by animation for source renderer `#1276`

### Security

Expand Down
35 changes: 28 additions & 7 deletions Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,14 @@ public override void Process(BuildContext context, MeshInfo2 target)
if (Component.copyEnablementAnimation)
CopyEnablementAnimation(context, target, meshInfos);

DoMerge(context, target, meshInfos, subMeshIndexMap, materials);
var targetAnimatedProperties = context.GetAnimationComponent(target.SourceRenderer)
.GetAllFloatProperties()
.Where(x => x.node.ComponentNodes.Any())
.Where(x => x.property.StartsWith("material.", StringComparison.Ordinal))
.Select(x => x.property["material.".Length..])
.ToHashSet();

DoMerge(context, target, meshInfos, subMeshIndexMap, materials, targetAnimatedProperties);
MergeBounds(target, meshInfos);

RemoveOldRenderers(target, meshInfos, Component.removeEmptyRendererObject);
Expand Down Expand Up @@ -105,7 +112,7 @@ public static void GenerateWarningsOrErrors(
MeshInfo2[] meshInfos
) {
Profiler.BeginSample("Material / Shader Parameter Animation Warnings");
MaterialParameterAnimationWarnings(meshInfos, context);
MaterialParameterAnimationWarnings(meshInfos, target, context);
Profiler.EndSample();

Profiler.BeginSample("Material Normal Configuration Check");
Expand Down Expand Up @@ -245,13 +252,14 @@ public static (int[][] subMeshIndexMap, List<(MeshTopology topology, Material? m
return (subMeshIndexMap, materials);
}

public static void DoMerge(
BuildContext context,
public static void DoMerge(BuildContext context,
MeshInfo2 target,
MeshInfo2[] meshInfos,
int[][] subMeshIndexMap,
List<(MeshTopology topology, Material? material)> materials
) {
List<(MeshTopology topology, Material? material)> materials,
ICollection<string>? targetAnimatedProperties) {
targetAnimatedProperties ??= Array.Empty<string>();

target.ClearMeshData();
target.SubMeshes.Capacity = Math.Max(target.SubMeshes.Capacity, materials.Count);
foreach (var material in materials)
Expand Down Expand Up @@ -311,6 +319,11 @@ TexCoordStatus TexCoordStatusMax(TexCoordStatus x, TexCoordStatus y) =>
// This invalidation doesn't affect to m_Enabled property of merged mesh.
context.RecordRemoveProperty(meshInfo.SourceRenderer, Props.EnabledFor(meshInfo.SourceRenderer));

// If both source and target have animation, it will conflict so we remove it from source,
// and forcibly keep target's animation.
foreach (var targetAnimatedProperty in targetAnimatedProperties)
context.RecordRemoveProperty(meshInfo.SourceRenderer, $"material.{targetAnimatedProperty}");

context.RecordMergeComponent(meshInfo.SourceRenderer, target.SourceRenderer);

target.Bones.AddRange(meshInfo.Bones);
Expand Down Expand Up @@ -406,8 +419,15 @@ from meshInfo in meshInfos
Profiler.EndSample();
}

private static void MaterialParameterAnimationWarnings(MeshInfo2[] sourceRenderers, BuildContext context)
private static void MaterialParameterAnimationWarnings(MeshInfo2[] sourceRenderers, MeshInfo2 target,
BuildContext context)
{
var targetAnimatedProperties = context.GetAnimationComponent(target.SourceRenderer)
.GetAllFloatProperties()
.Where(x => x.node.ComponentNodes.Any())
.Where(x => x.property.StartsWith("material.", StringComparison.Ordinal))
.Select(x => x.property["material.".Length..])
.ToHashSet();
var properties = new Dictionary<string, List<(RootPropModNode<FloatValueInfo>, MeshInfo2)>>();
var materialByMeshInfo2 = new List<(MeshInfo2 meshInfo2, List<Material> materials)>();
foreach (var meshInfo2 in sourceRenderers)
Expand Down Expand Up @@ -439,6 +459,7 @@ private static void MaterialParameterAnimationWarnings(MeshInfo2[] sourceRendere

foreach (var (propertyName, animatingProperties) in properties)
{
if (targetAnimatedProperties.Contains(propertyName)) continue;
var rendererBySource = new Dictionary<AnimationLocation, HashSet<MeshInfo2>>();

foreach (var (property, renderer) in animatingProperties)
Expand Down
6 changes: 2 additions & 4 deletions Editor/Processors/TraceAndOptimize/AutoMergeSkinnedMesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,7 @@ private static void MergeStaticSkinnedMesh(

var (subMeshIndexMap, materials) = createSubMeshes(meshInfosArray);

MergeSkinnedMeshProcessor.DoMerge(context, newMeshInfo, meshInfosArray, subMeshIndexMap,
materials);
MergeSkinnedMeshProcessor.DoMerge(context, newMeshInfo, meshInfosArray, subMeshIndexMap, materials, null);

// We process FindUnusedObjects after this pass so we wipe empty renderer object in that pass
MergeSkinnedMeshProcessor.RemoveOldRenderers(newMeshInfo, meshInfosArray,
Expand Down Expand Up @@ -269,8 +268,7 @@ private static void MergeAnimatingSkinnedMesh(

var (subMeshIndexMap, materials) = createSubMeshes(meshInfosArray);

MergeSkinnedMeshProcessor.DoMerge(context, newMeshInfo, meshInfosArray, subMeshIndexMap,
materials);
MergeSkinnedMeshProcessor.DoMerge(context, newMeshInfo, meshInfosArray, subMeshIndexMap, materials, null);

// We process FindUnusedObjects after this pass so we wipe empty renderer object in that pass
MergeSkinnedMeshProcessor.RemoveOldRenderers(newMeshInfo, meshInfosArray,
Expand Down

0 comments on commit 71acd88

Please sign in to comment.