You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
7.9 KiB
163 lines
7.9 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
using System.Text; |
|
using UnityEditor.Rendering.Universal.Converters; |
|
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 => "Need to update all Animation Clips. This will run after Materials has been converted."; |
|
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); |
|
} |
|
} |
|
}
|
|
|