UnityGame/Library/PackageCache/com.unity.render-pipelines.universal/Editor/Converter/AnimationClipConverter.cs
2024-10-27 10:53:47 +03:00

164 lines
7.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEditor.Rendering.Universal;
using ClipPath = UnityEditor.Rendering.AnimationClipUpgrader.ClipPath;
using ClipProxy = UnityEditor.Rendering.AnimationClipUpgrader.AnimationClipProxy;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.Rendering.Universal
{
internal sealed class AnimationClipConverter : RenderPipelineConverter
{
public override string name => "Animation Clip Converter";
public override string info => "This converter updates all animation clips so that they reference the correct Materials.";
public override string category { get; }
public override Type container => typeof(BuiltInToURPConverterContainer);
List<GlobalObjectId> m_AssetsToConvert = new List<GlobalObjectId>(64);
IDictionary<AnimationClipUpgrader.IAnimationClip, (ClipPath Path, EditorCurveBinding[] Bindings, SerializedShaderPropertyUsage Usage, IDictionary<EditorCurveBinding, string> PropertyRenames)> m_ClipData =
new Dictionary<AnimationClipUpgrader.IAnimationClip, (ClipPath Path, EditorCurveBinding[] Bindings, SerializedShaderPropertyUsage Usage, IDictionary<EditorCurveBinding, string> PropertyRenames)>();
public override void OnInitialize(InitializeConverterContext ctx, Action callback)
{
// get paths to all animation clips
var clipPaths = AssetDatabase.FindAssets("t:AnimationClip")
.Select(p => (ClipPath)AssetDatabase.GUIDToAssetPath(p))
.ToArray();
// retrieve clip assets with material animation
m_ClipData = AnimationClipUpgrader.GetAssetDataForClipsFiltered(clipPaths);
// collect all clips and add them to the context
var keys = m_ClipData.Keys.ToArray();
var clipIds = new GlobalObjectId[keys.Length];
GlobalObjectId.GetGlobalObjectIdsSlow(keys.Select(c => c.Clip as UnityObject).ToArray(), clipIds);
for (int i = 0; i < keys.Length; ++i)
{
AnimationClipUpgrader.IAnimationClip key = keys[i];
var cd = m_ClipData[key];
var clip = key.Clip;
var item = new ConverterItemDescriptor()
{
name = clip.name,
info = cd.Path,
};
// TODO: need to know how materials will be upgraded in order to generate warnings
m_AssetsToConvert.Add(clipIds[i]);
ctx.AddAssetToConvert(item);
}
callback.Invoke();
}
public override void OnPreRun()
{
// get paths to all animation clips
var clipPaths = new HashSet<ClipPath>(m_ClipData.Values.Select(cd => cd.Path));
// get paths to all prefabs and scenes in order to inspect clip usage
var prefabPaths = AssetDatabase.FindAssets("t:Prefab")
.Select(p => (AnimationClipUpgrader.PrefabPath)AssetDatabase.GUIDToAssetPath(p))
.ToArray();
var scenePaths = AssetDatabase.FindAssets("t:Scene")
.Select(p => (AnimationClipUpgrader.ScenePath)AssetDatabase.GUIDToAssetPath(p))
.ToArray();
// create table mapping all upgrade paths to new shaders
var upgraders = new UniversalRenderPipelineMaterialUpgrader().upgraders;
var allUpgradePathsToNewShaders = UpgradeUtility.GetAllUpgradePathsToShaders(upgraders);
// TODO: could pass in upgrade paths used by materials in the future
// retrieve interdependencies with prefabs to figure out which clips can be safely upgraded
AnimationClipUpgrader.GetClipDependencyMappings(clipPaths, prefabPaths, out var clipPrefabDependents, out var prefabDependencies);
AnimationClipUpgrader.GatherClipsUsageInDependentPrefabs(
clipPrefabDependents, prefabDependencies, m_ClipData, allUpgradePathsToNewShaders, default, default);
// do the same for clips used by scenes
AnimationClipUpgrader.GetClipDependencyMappings(clipPaths, scenePaths, out var clipSceneDependents, out var sceneDependencies);
AnimationClipUpgrader.GatherClipsUsageInDependentScenes(
clipSceneDependents, sceneDependencies, m_ClipData, allUpgradePathsToNewShaders, default, default);
}
HashSet<(AnimationClipUpgrader.IAnimationClip Clip, ClipPath Path, SerializedShaderPropertyUsage Usage)> m_Upgraded =
new HashSet<(AnimationClipUpgrader.IAnimationClip Clip, ClipPath Path, SerializedShaderPropertyUsage Usage)>();
HashSet<(AnimationClipUpgrader.IAnimationClip Clip, ClipPath Path, SerializedShaderPropertyUsage Usage)> m_NotUpgraded =
new HashSet<(AnimationClipUpgrader.IAnimationClip Clip, ClipPath Path, SerializedShaderPropertyUsage Usage)>();
IDictionary<AnimationClipUpgrader.IAnimationClip, (ClipPath Path, EditorCurveBinding[] Bindings, SerializedShaderPropertyUsage Usage, IDictionary<EditorCurveBinding, string> PropertyRenames)> m_TempClipData =
new Dictionary<AnimationClipUpgrader.IAnimationClip, (ClipPath Path, EditorCurveBinding[] Bindings, SerializedShaderPropertyUsage Usage, IDictionary<EditorCurveBinding, string> PropertyRenames)>();
public override void OnRun(ref RunItemContext ctx)
{
// filter flags are used to determine which clips to skip over during upgrade process
// we want to process all clips that are not ambiguously upgraded
const SerializedShaderPropertyUsage kFilterFlags =
~(
SerializedShaderPropertyUsage.UsedByUpgraded
| SerializedShaderPropertyUsage.UsedByNonUpgraded
);
const SerializedShaderPropertyUsage kSuccessFlags =
SerializedShaderPropertyUsage.UsedByUpgraded;
var clipKey = (ClipProxy)GlobalObjectId.GlobalObjectIdentifierToObjectSlow(m_AssetsToConvert[ctx.item.index]);
m_TempClipData.Clear();
m_TempClipData[clipKey] = m_ClipData[clipKey];
m_Upgraded.Clear();
m_NotUpgraded.Clear();
AnimationClipUpgrader.UpgradeClips(m_TempClipData, kFilterFlags, m_Upgraded, m_NotUpgraded, default);
var usage = m_TempClipData[clipKey].Usage;
// Success
if ((usage & kSuccessFlags) != 0 && (usage & kFilterFlags) == 0)
return;
if (usage == SerializedShaderPropertyUsage.Unknown)
{
ctx.didFail = true;
ctx.info = L10n.Tr("The animation clip is not used by any objects with renderers currently in the project, so it may not be safe to automatically upgrade.");
return;
}
var sb = new StringBuilder();
sb.Append(L10n.Tr("The animation clip was not modified for one or more reasons:"));
if ((usage & SerializedShaderPropertyUsage.UsedByAmbiguouslyUpgraded) != 0)
{
ctx.didFail = true;
sb.Append(L10n.Tr("\n - The animation clip is used by objects with materials that took different upgrade paths for the animated property."));
}
if ((usage & SerializedShaderPropertyUsage.UsedByNonUpgraded) != 0)
{
ctx.didFail = true;
sb.Append(L10n.Tr("\n - The animation clip is used by objects with materials that have not been upgraded."));
}
if (ctx.didFail)
ctx.info = sb.ToString();
}
public override void OnClicked(int index)
{
var id = m_AssetsToConvert[index];
var clip = GlobalObjectId.GlobalObjectIdentifierToObjectSlow(id);
if (clip == null)
return;
EditorGUIUtility.PingObject(clip);
}
}
}