164 lines
7.9 KiB
C#
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);
|
||
|
}
|
||
|
}
|
||
|
}
|