Rasagar/Library/PackageCache/com.unity.formats.fbx/Editor/IExportData.cs
2024-08-30 17:33:54 +03:00

210 lines
7.9 KiB
C#

using UnityEngine;
using UnityEngine.Timeline;
using System.Collections.Generic;
using UnityEngine.Playables;
namespace UnityEditor.Formats.Fbx.Exporter
{
/// <summary>
/// Export data containing extra information required to export
/// </summary>
internal interface IExportData
{
HashSet<GameObject> Objects { get; }
}
/// <summary>
/// Export data containing what to export when
/// exporting animation only.
/// </summary>
internal class AnimationOnlyExportData : IExportData
{
// map from animation clip to GameObject that has Animation/Animator
// component containing clip
public Dictionary<AnimationClip, GameObject> animationClips;
// set of all GameObjects to export
public HashSet<GameObject> goExportSet;
public HashSet<GameObject> Objects { get { return goExportSet; } }
// map from GameObject to component type to export
public Dictionary<GameObject, System.Type> exportComponent;
// first clip to export
public AnimationClip defaultClip;
public AnimationOnlyExportData(
Dictionary<AnimationClip, GameObject> animClips,
HashSet<GameObject> exportSet,
Dictionary<GameObject, System.Type> exportComponent
)
{
this.animationClips = animClips;
this.goExportSet = exportSet;
this.exportComponent = exportComponent;
this.defaultClip = null;
}
public AnimationOnlyExportData()
{
this.animationClips = new Dictionary<AnimationClip, GameObject>();
this.goExportSet = new HashSet<GameObject>();
this.exportComponent = new Dictionary<GameObject, System.Type>();
this.defaultClip = null;
}
/// <summary>
/// collect all object dependencies for given animation clip
/// </summary>
public void CollectDependencies(
AnimationClip animClip,
GameObject rootObject,
IExportOptions exportOptions
)
{
Debug.Assert(rootObject != null);
Debug.Assert(exportOptions != null);
if (this.animationClips.ContainsKey(animClip))
{
// we have already exported gameobjects for this clip
return;
}
// NOTE: the object (animationRootObject) containing the animation is not necessarily animated
// when driven by an animator or animation component.
this.animationClips.Add(animClip, rootObject);
foreach (EditorCurveBinding uniCurveBinding in AnimationUtility.GetCurveBindings(animClip))
{
Object uniObj = AnimationUtility.GetAnimatedObject(rootObject, uniCurveBinding);
if (!uniObj)
{
continue;
}
GameObject unityGo = ModelExporter.GetGameObject(uniObj);
if (!unityGo)
{
continue;
}
if (!exportOptions.AnimateSkinnedMesh && unityGo.GetComponent<SkinnedMeshRenderer>())
{
continue;
}
// If we have a clip driving a camera or light then force the export of FbxNodeAttribute
// so that they point the right way when imported into Maya.
if (unityGo.GetComponent<Light>())
this.exportComponent[unityGo] = typeof(Light);
else if (unityGo.GetComponent<Camera>())
this.exportComponent[unityGo] = typeof(Camera);
else if ((uniCurveBinding.type == typeof(SkinnedMeshRenderer)) && unityGo.GetComponent<SkinnedMeshRenderer>())
{
// only export mesh if there are animation keys for it (e.g. for blendshapes)
if (FbxPropertyChannelPair.TryGetValue(uniCurveBinding.propertyName, out FbxPropertyChannelPair[] channelPairs))
{
this.exportComponent[unityGo] = typeof(SkinnedMeshRenderer);
}
}
this.goExportSet.Add(unityGo);
}
}
/// <summary>
/// collect all objects dependencies for animation clips.
/// </summary>
public void CollectDependencies(
AnimationClip[] animClips,
GameObject rootObject,
IExportOptions exportOptions
)
{
Debug.Assert(rootObject != null);
Debug.Assert(exportOptions != null);
foreach (var animClip in animClips)
{
CollectDependencies(animClip, rootObject, exportOptions);
}
}
/// <summary>
/// Get the GameObject that the clip is bound to in the timeline.
/// </summary>
/// <param name="timelineClip"></param>
/// <returns>The GameObject bound to the timeline clip or null if none.</returns>
private static GameObject GetGameObjectBoundToTimelineClip(TimelineClip timelineClip, PlayableDirector director = null)
{
object parentTrack = timelineClip.GetParentTrack();
AnimationTrack animTrack = parentTrack as AnimationTrack;
var inspectedDirector = director ? director : UnityEditor.Timeline.TimelineEditor.inspectedDirector;
if (!inspectedDirector)
{
Debug.LogWarning("No Timeline selected in inspector, cannot retrieve GameObject bound to track");
return null;
}
Object animationTrackObject = inspectedDirector.GetGenericBinding(animTrack);
GameObject animationTrackGO = null;
if (animationTrackObject is GameObject)
{
animationTrackGO = animationTrackObject as GameObject;
}
else if (animationTrackObject is Animator)
{
animationTrackGO = (animationTrackObject as Animator).gameObject;
}
if (animationTrackGO == null)
{
Debug.LogErrorFormat("Could not export animation track object of type {0}", animationTrackObject.GetType().Name);
return null;
}
return animationTrackGO;
}
/// <summary>
/// Get the GameObject and it's corresponding animation clip from the given timeline clip.
/// </summary>
/// <param name="timelineClip"></param>
/// <returns>KeyValuePair containing GameObject and corresponding AnimationClip</returns>
public static KeyValuePair<GameObject, AnimationClip> GetGameObjectAndAnimationClip(TimelineClip timelineClip, PlayableDirector director = null)
{
var animationTrackGO = GetGameObjectBoundToTimelineClip(timelineClip, director);
if (!animationTrackGO)
{
return new KeyValuePair<GameObject, AnimationClip>();
}
return new KeyValuePair<GameObject, AnimationClip>(animationTrackGO, timelineClip.animationClip);
}
/// <summary>
/// Get the filename of the format {model}@{anim}.fbx from the given timeline clip
/// </summary>
/// <param name="timelineClip"></param>
/// <returns>filename for use for exporting animation clip</returns>
public static string GetFileName(TimelineClip timelineClip)
{
// if the timeline clip name already contains an @, then take this as the
// filename to avoid duplicate @
if (timelineClip.displayName.Contains("@"))
{
return timelineClip.displayName;
}
var goBound = GetGameObjectBoundToTimelineClip(timelineClip);
if (goBound == null)
{
return timelineClip.displayName;
}
return string.Format("{0}@{1}", goBound.name, timelineClip.displayName);
}
}
}