264 lines
13 KiB
C#
Raw Normal View History

2025-03-11 15:30:07 +08:00
using UnityEngine;
namespace UnityEditor.Formats.Fbx.Exporter
{
[CustomEditor (typeof(ExportModelSettings))]
internal class ExportModelSettingsEditor : UnityEditor.Editor
{
private const float DefaultLabelWidth = 175;
private const float DefaultFieldOffset = 18;
public float LabelWidth { get; set; } = DefaultLabelWidth;
public float FieldOffset { get; set; } = DefaultFieldOffset;
private string[] exportFormatOptions = new string[]{ "ASCII", "Binary" };
private string[] includeOptions = new string[]{"Model(s) Only", "Animation Only", "Model(s) + Animation"};
private string[] lodOptions = new string[]{"All Levels", "Highest", "Lowest"};
public const string singleHierarchyOption = "Local Pivot";
public const string multiHerarchyOption = "Local Centered";
private string hierarchyDepOption = singleHierarchyOption;
private string[] objPositionOptions { get { return new string[]{hierarchyDepOption, "World Absolute"}; }}
private bool disableIncludeDropdown = false;
private bool m_exportingOutsideProject = false;
public void SetExportingOutsideProject(bool val)
{
m_exportingOutsideProject = val;
}
public void SetIsSingleHierarchy(bool singleHierarchy){
if (singleHierarchy) {
hierarchyDepOption = singleHierarchyOption;
return;
}
hierarchyDepOption = multiHerarchyOption;
}
public void DisableIncludeDropdown(bool disable){
disableIncludeDropdown = disable;
}
public override void OnInspectorGUI ()
{
var exportSettings = ((ExportModelSettings)target).info;
EditorGUIUtility.labelWidth = LabelWidth;
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField(new GUIContent("Export Format", "Export the FBX file in the standard binary format." +
" Select ASCII to export the FBX file in ASCII format."), GUILayout.Width(LabelWidth - FieldOffset));
exportSettings.SetExportFormat((ExportSettings.ExportFormat)EditorGUILayout.Popup((int)exportSettings.ExportFormat, exportFormatOptions) );
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField(new GUIContent("Include", "Select whether to export models, animation or both."), GUILayout.Width(LabelWidth - FieldOffset));
EditorGUI.BeginDisabledGroup(disableIncludeDropdown);
exportSettings.SetModelAnimIncludeOption((ExportSettings.Include)EditorGUILayout.Popup((int)exportSettings.ModelAnimIncludeOption, includeOptions));
EditorGUI.EndDisabledGroup ();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField(new GUIContent("LOD level", "Select which LOD to export."), GUILayout.Width(LabelWidth - FieldOffset));
// greyed out if animation only
EditorGUI.BeginDisabledGroup(exportSettings.ModelAnimIncludeOption == ExportSettings.Include.Anim);
exportSettings.SetLODExportType((ExportSettings.LODExportType)EditorGUILayout.Popup((int)exportSettings.LODExportType, lodOptions));
EditorGUI.EndDisabledGroup ();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField(new GUIContent("Object(s) Position", "Select an option for exporting object's transform."), GUILayout.Width(LabelWidth - FieldOffset));
// greyed out if animation only
EditorGUI.BeginDisabledGroup(exportSettings.ModelAnimIncludeOption == ExportSettings.Include.Anim);
exportSettings.SetObjectPosition((ExportSettings.ObjectPosition)EditorGUILayout.Popup((int)exportSettings.ObjectPosition, objPositionOptions));
EditorGUI.EndDisabledGroup ();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField(new GUIContent("Animated Skinned Mesh",
"If checked, animation on objects with skinned meshes will be exported"), GUILayout.Width(LabelWidth - FieldOffset));
// greyed out if model
EditorGUI.BeginDisabledGroup(exportSettings.ModelAnimIncludeOption == ExportSettings.Include.Model);
exportSettings.SetAnimatedSkinnedMesh(EditorGUILayout.Toggle(exportSettings.AnimateSkinnedMesh));
EditorGUI.EndDisabledGroup ();
GUILayout.EndHorizontal ();
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField(new GUIContent("Compatible Naming",
"In Maya some symbols such as spaces and accents get replaced when importing an FBX " +
"(e.g. \"foo bar\" becomes \"fooFBXASC032bar\"). " +
"On export, convert the names of GameObjects so they are Maya compatible." +
(exportSettings.UseMayaCompatibleNames ? "" :
"\n\nWARNING: Disabling this feature may result in lost material connections," +
" and unexpected character replacements in Maya.")),
GUILayout.Width(LabelWidth - FieldOffset));
exportSettings.SetUseMayaCompatibleNames(EditorGUILayout.Toggle (exportSettings.UseMayaCompatibleNames));
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField(new GUIContent("Export Unrendered",
"If checked, meshes will be exported even if they don't have a Renderer component."), GUILayout.Width(LabelWidth - FieldOffset));
// greyed out if animation only
EditorGUI.BeginDisabledGroup(exportSettings.ModelAnimIncludeOption == ExportSettings.Include.Anim);
exportSettings.SetExportUnredererd(EditorGUILayout.Toggle(exportSettings.ExportUnrendered));
EditorGUI.EndDisabledGroup ();
GUILayout.EndHorizontal ();
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField(new GUIContent("Preserve Import Settings",
"If checked, the import settings from the overwritten FBX will be carried over to the new version."), GUILayout.Width(LabelWidth - FieldOffset));
// greyed out if exporting outside assets folder
EditorGUI.BeginDisabledGroup(m_exportingOutsideProject);
exportSettings.SetPreserveImportSettings(EditorGUILayout.Toggle(exportSettings.PreserveImportSettings));
EditorGUI.EndDisabledGroup();
GUILayout.EndHorizontal();
}
}
internal interface IExportOptions {
ExportSettings.ExportFormat ExportFormat { get; }
ExportSettings.Include ModelAnimIncludeOption { get; }
ExportSettings.LODExportType LODExportType { get; }
ExportSettings.ObjectPosition ObjectPosition { get; }
bool AnimateSkinnedMesh { get; }
bool UseMayaCompatibleNames { get; }
bool AllowSceneModification { get; }
bool ExportUnrendered { get; }
bool PreserveImportSettings { get; }
Transform AnimationSource { get; }
Transform AnimationDest { get; }
}
internal abstract class ExportOptionsSettingsBase<T> : ScriptableObject where T : ExportOptionsSettingsSerializeBase, new()
{
[SerializeField]
private T m_info = new T();
public T info
{
get { return m_info; }
set { m_info = value; }
}
public override bool Equals(object e)
{
var expOptions = e as ExportOptionsSettingsBase<T>;
if(expOptions == null)
{
return false;
}
return this.info.Equals(expOptions.info);
}
public override int GetHashCode()
{
return this.info.GetHashCode();
}
}
internal class ExportModelSettings : ExportOptionsSettingsBase<ExportModelSettingsSerialize>
{}
[System.Serializable]
internal abstract class ExportOptionsSettingsSerializeBase : IExportOptions
{
[SerializeField]
private ExportSettings.ExportFormat exportFormat = ExportSettings.ExportFormat.ASCII;
[SerializeField]
private bool animatedSkinnedMesh = false;
[SerializeField]
private bool mayaCompatibleNaming = true;
[System.NonSerialized]
private Transform animSource;
[System.NonSerialized]
private Transform animDest;
public ExportSettings.ExportFormat ExportFormat { get { return exportFormat; } }
public void SetExportFormat(ExportSettings.ExportFormat format){ this.exportFormat = format; }
public bool AnimateSkinnedMesh { get { return animatedSkinnedMesh; } }
public void SetAnimatedSkinnedMesh(bool animatedSkinnedMesh){ this.animatedSkinnedMesh = animatedSkinnedMesh; }
public bool UseMayaCompatibleNames { get { return mayaCompatibleNaming; } }
public void SetUseMayaCompatibleNames(bool useMayaCompNames){ this.mayaCompatibleNaming = useMayaCompNames; }
public Transform AnimationSource { get { return animSource; } }
public void SetAnimationSource(Transform source) { this.animSource = source; }
public Transform AnimationDest { get { return animDest; } }
public void SetAnimationDest(Transform dest) { this.animDest = dest; }
public abstract ExportSettings.Include ModelAnimIncludeOption { get; }
public abstract ExportSettings.LODExportType LODExportType { get; }
public abstract ExportSettings.ObjectPosition ObjectPosition { get; }
public abstract bool ExportUnrendered { get; }
public virtual bool PreserveImportSettings { get { return false; } }
public abstract bool AllowSceneModification { get; }
public override bool Equals(object e)
{
var expOptions = e as ExportOptionsSettingsSerializeBase;
if (expOptions == null)
{
return false;
}
return animatedSkinnedMesh == expOptions.animatedSkinnedMesh &&
mayaCompatibleNaming == expOptions.mayaCompatibleNaming &&
exportFormat == expOptions.exportFormat;
}
public override int GetHashCode()
{
return (animatedSkinnedMesh ? 1 : 0) | ((mayaCompatibleNaming ? 1 : 0) << 1) | ((int)exportFormat << 2);
}
}
[System.Serializable]
internal class ExportModelSettingsSerialize : ExportOptionsSettingsSerializeBase
{
[SerializeField]
private ExportSettings.Include include = ExportSettings.Include.ModelAndAnim;
[SerializeField]
private ExportSettings.LODExportType lodLevel = ExportSettings.LODExportType.All;
[SerializeField]
private ExportSettings.ObjectPosition objectPosition = ExportSettings.ObjectPosition.LocalCentered;
[SerializeField]
private bool exportUnrendered = true;
[SerializeField]
private bool preserveImportSettings = false;
public override ExportSettings.Include ModelAnimIncludeOption { get { return include; } }
public void SetModelAnimIncludeOption(ExportSettings.Include include) { this.include = include; }
public override ExportSettings.LODExportType LODExportType { get { return lodLevel; } }
public void SetLODExportType(ExportSettings.LODExportType lodLevel){ this.lodLevel = lodLevel; }
public override ExportSettings.ObjectPosition ObjectPosition { get { return objectPosition; } }
public void SetObjectPosition(ExportSettings.ObjectPosition objPos){ this.objectPosition = objPos; }
public override bool ExportUnrendered { get { return exportUnrendered; } }
public void SetExportUnredererd(bool exportUnrendered){ this.exportUnrendered = exportUnrendered; }
public override bool PreserveImportSettings { get { return preserveImportSettings; } }
public void SetPreserveImportSettings(bool preserveImportSettings){ this.preserveImportSettings = preserveImportSettings; }
public override bool AllowSceneModification { get { return false; } }
public override bool Equals(object e)
{
var expOptions = e as ExportModelSettingsSerialize;
if (expOptions == null)
{
return false;
}
return base.Equals(e) &&
include == expOptions.include &&
lodLevel == expOptions.lodLevel &&
objectPosition == expOptions.objectPosition &&
exportUnrendered == expOptions.exportUnrendered &&
preserveImportSettings == expOptions.preserveImportSettings;
}
public override int GetHashCode()
{
var bitmask = base.GetHashCode();
bitmask = (bitmask << 2) ^ (int)include;
bitmask = (bitmask << 2) ^ (int)lodLevel;
bitmask = (bitmask << 2) ^ (int)objectPosition;
bitmask = (bitmask << 1) | (exportUnrendered ? 1 : 0);
bitmask = (bitmask << 1) | (preserveImportSettings ? 1 : 0);
return bitmask;
}
}
}