Unity Chan 工程分享 - URP渲染实现 Unity版本:2019.4
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

254 行
10 KiB

using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEditor.Localization.Editor;
namespace Unity.Animations.SpringBones
{
public class LoadSpringBoneSetupWindow : EditorWindow
{
private static class Styles
{
public static readonly string editorWindowTitle = Localization.Tr("Load spring bone setup");
public static readonly string stopPlayModeMessage = Localization.Tr("Do not setup in Play Mode");
public static readonly string selectObjectRootsMessage = Localization.Tr("Select parent object of the spring bone");
public static readonly string resultFormat = Localization.Tr("Set up complete:{0}\nNumber of bones: {1} Number of colliders: {2}");
public static readonly string csvFile = Localization.Tr("CSV File");
public static readonly string textFile = Localization.Tr("Text File");
public static readonly string loadSpringBoneSetup = Localization.Tr("Load spring bone setup");
public static readonly string errorFormat = Localization.Tr(
"SpringBone setup failed.\n"
+ "Souce data may contain errors,\n"
+ "or the data don't match the character.\n"
+ "Please refer console logs for further info.\n"
+ "\n"
+ "Character: {0}\n"
+ "\n"
+ "Path: {1}");
public static readonly string springBoneSetup = Localization.Tr("SpringBone Setup");
public static readonly string springBoneSetupFailedFormat = Localization.Tr("SpringBone Setup failed:{0}\nPath:{1}");
public static readonly string labelSpringBoneRoot = Localization.Tr("SpringBone Root");
public static readonly GUIContent labelLoadingConfig = new GUIContent(Localization.Tr("Loading Configuration"));
public static readonly GUIContent labelSpringBone = new GUIContent(Localization.Tr("SpringBone"));
public static readonly GUIContent labelCollider = new GUIContent(Localization.Tr("Collider"));
public static readonly GUIContent labelSelectFromRoot = new GUIContent(Localization.Tr("Get root from selection"));
public static readonly GUIContent labelSetupLoadCSV = new GUIContent(Localization.Tr("Set up from CSV file"));
}
public static void ShowWindow()
{
var editorWindow = GetWindow<LoadSpringBoneSetupWindow>(Styles.editorWindowTitle);
if (editorWindow != null)
{
editorWindow.SelectObjectsFromSelection();
}
}
public static T DoObjectPicker<T>
(
string label,
T currentObject,
int uiWidth,
int uiHeight,
ref int yPos
) where T : UnityEngine.Object
{
var uiRect = new Rect(UISpacing, yPos, LabelWidth, uiHeight);
GUI.Label(uiRect, label, SpringBoneGUIStyles.LabelStyle);
uiRect.x = LabelWidth + UISpacing;
uiRect.width = uiWidth - uiRect.x + UISpacing;
yPos += uiHeight + UISpacing;
return EditorGUI.ObjectField(uiRect, currentObject, typeof(T), true) as T;
}
// private
private const int UIRowHeight = 24;
private const int UISpacing = 8;
private const int LabelWidth = 200;
private GameObject springBoneRoot;
private DynamicsSetup.ImportSettings importSettings;
private void SelectObjectsFromSelection()
{
springBoneRoot = null;
if (Selection.objects.Length > 0)
{
springBoneRoot = Selection.objects[0] as GameObject;
}
if (springBoneRoot == null)
{
var characterRootComponentTypes = new System.Type[] {
typeof(SpringManager),
typeof(Animation),
typeof(Animator)
};
springBoneRoot = characterRootComponentTypes
.Select(type => FindObjectOfType(type) as Component)
.Where(component => component != null)
.Select(component => component.gameObject)
.FirstOrDefault();
}
}
private void ShowImportSettingsUI(ref Rect uiRect)
{
if (importSettings == null)
{
importSettings = new DynamicsSetup.ImportSettings();
}
GUI.Label(uiRect, Styles.labelLoadingConfig, SpringBoneGUIStyles.HeaderLabelStyle);
uiRect.y += uiRect.height;
importSettings.ImportSpringBones = GUI.Toggle(uiRect, importSettings.ImportSpringBones, Styles.labelSpringBone, SpringBoneGUIStyles.ToggleStyle);
uiRect.y += uiRect.height;
importSettings.ImportCollision = GUI.Toggle(uiRect, importSettings.ImportCollision, Styles.labelCollider, SpringBoneGUIStyles.ToggleStyle);
uiRect.y += uiRect.height;
}
private void OnGUI()
{
SpringBoneGUIStyles.ReacquireStyles();
const int ButtonHeight = 30;
var uiWidth = (int)position.width - UISpacing * 2;
var yPos = UISpacing;
springBoneRoot = DoObjectPicker(Styles.labelSpringBoneRoot, springBoneRoot, uiWidth, UIRowHeight, ref yPos);
var buttonRect = new Rect(UISpacing, yPos, uiWidth, ButtonHeight);
if (GUI.Button(buttonRect, Styles.labelSelectFromRoot, SpringBoneGUIStyles.ButtonStyle))
{
SelectObjectsFromSelection();
}
yPos += ButtonHeight + UISpacing;
buttonRect.y = yPos;
ShowImportSettingsUI(ref buttonRect);
string errorMessage;
if (IsOkayToSetup(out errorMessage))
{
if (GUI.Button(buttonRect, Styles.labelSetupLoadCSV, SpringBoneGUIStyles.ButtonStyle))
{
BrowseAndLoadSpringSetup();
}
}
else
{
const int MessageHeight = 24;
var uiRect = new Rect(UISpacing, buttonRect.y, uiWidth, MessageHeight);
GUI.Label(uiRect, errorMessage, SpringBoneGUIStyles.HeaderLabelStyle);
}
}
private bool IsOkayToSetup(out string errorMessage)
{
errorMessage = "";
if (EditorApplication.isPlaying)
{
errorMessage = Styles.stopPlayModeMessage;
return false;
}
if (springBoneRoot == null)
{
errorMessage = Styles.selectObjectRootsMessage;
return false;
}
return true;
}
private static T FindHighestComponentInHierarchy<T>(GameObject startObject) where T : Component
{
T highestComponent = null;
if (startObject != null)
{
var transform = startObject.transform;
while (transform != null)
{
var component = transform.GetComponent<T>();
if (component != null) { highestComponent = component; }
transform = transform.parent;
}
}
return highestComponent;
}
private class BuildDynamicsAction : SpringBoneSetupErrorWindow.IConfirmAction
{
public BuildDynamicsAction
(
DynamicsSetup newSetup,
string newPath,
GameObject newSpringBoneRoot
)
{
setup = newSetup;
path = newPath;
springBoneRoot = newSpringBoneRoot;
}
public void Perform()
{
setup.Build();
AssetDatabase.Refresh();
var boneCount = springBoneRoot.GetComponentsInChildren<SpringBone>(true).Length;
var colliderCount = SpringColliderSetup.GetColliderTypes()
.Sum(type => springBoneRoot.GetComponentsInChildren(type, true).Length);
var resultMessage = string.Format(Styles.resultFormat, path, boneCount, colliderCount);
Debug.Log(resultMessage);
}
private DynamicsSetup setup;
private string path;
private GameObject springBoneRoot;
}
private void BrowseAndLoadSpringSetup()
{
if (!IsOkayToSetup(out var checkErrorMessage))
{
Debug.LogError(checkErrorMessage);
return;
}
// var initialPath = "";
var initialDirectory = ""; // System.IO.Path.GetDirectoryName(initialPath);
var fileFilters = new string[] { Styles.csvFile, "csv", Styles.textFile, "txt" };
var path = EditorUtility.OpenFilePanelWithFilters(
Styles.loadSpringBoneSetup, initialDirectory, fileFilters);
if (path.Length == 0) { return; }
var sourceText = FileUtil.ReadAllText(path);
if (string.IsNullOrEmpty(sourceText)) { return; }
var parsedSetup = DynamicsSetup.ParseFromRecordText(springBoneRoot, springBoneRoot, sourceText, importSettings);
if (parsedSetup.Setup != null)
{
var buildAction = new BuildDynamicsAction(parsedSetup.Setup, path, springBoneRoot);
if (parsedSetup.HasErrors)
{
SpringBoneSetupErrorWindow.ShowWindow(springBoneRoot, springBoneRoot, path, parsedSetup.Errors, buildAction);
}
else
{
buildAction.Perform();
}
}
else
{
var resultErrorMessage = string.Format(Styles.errorFormat, springBoneRoot.name, path);
EditorUtility.DisplayDialog(Styles.springBoneSetup, resultErrorMessage, "OK");
Debug.LogFormat(LogType.Error, LogOption.None, springBoneRoot,
Styles.springBoneSetupFailedFormat, springBoneRoot.name, path);
}
Close();
}
}
}