119 lines
4.9 KiB
C#
119 lines
4.9 KiB
C#
using Sirenix.OdinInspector.Editor;
|
||
using UnityEditor;
|
||
using UnityEditor.SceneManagement;
|
||
using UnityEngine;
|
||
|
||
[CustomEditor(typeof(PostProcessInstructor))]
|
||
public class PostProcessInstructorInspector : OdinEditor
|
||
{
|
||
private PostProcessInstructor Target => target as PostProcessInstructor;
|
||
|
||
public override void OnInspectorGUI()
|
||
{
|
||
base.OnInspectorGUI();
|
||
|
||
EditorGUILayout.Space();
|
||
|
||
var postProcessInstructors = FindObjectsOfType<PostProcessInstructor>();
|
||
|
||
using (new EditorGUILayout.HorizontalScope())
|
||
{
|
||
EditorGUI.BeginDisabledGroup(!Target.enableModelSlicing || Target.ground == null || Target.rootsToSlice == null || Target.rootsToSlice.Count == 0);
|
||
if (GUILayout.Button("切割模型"))
|
||
{
|
||
SliceModels();
|
||
}
|
||
EditorGUI.EndDisabledGroup();
|
||
|
||
if (GUILayout.Button("后处理"))
|
||
{
|
||
ObjectPostProcessorManager.Instance.PostProcess(Target);
|
||
}
|
||
|
||
if (postProcessInstructors.Length > 1 && GUILayout.Button("多节点后处理"))
|
||
{
|
||
ObjectPostProcessorManager.Instance.PostProcessMore(postProcessInstructors);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行模型切割操作
|
||
/// </summary>
|
||
private void SliceModels()
|
||
{
|
||
if (!Target.enableModelSlicing || Target.ground == null || Target.rootsToSlice == null || Target.rootsToSlice.Count == 0)
|
||
{
|
||
Debug.LogWarning("无法执行切割:请确保启用了模型切割功能,并设置了地面和需要切割的模型节点");
|
||
return;
|
||
}
|
||
|
||
// 创建SlicerRoot节点,作为切割后模型的父节点(仅当保留原始模型时使用)
|
||
GameObject slicerRootObj = null;
|
||
Transform slicerRoot = null;
|
||
|
||
if (Target.preserveOriginalModels)
|
||
{
|
||
// 保留原始模型时,创建SlicerRoot作为切割结果的容器
|
||
slicerRootObj = new GameObject("SlicerRoot");
|
||
slicerRootObj.transform.parent = Target.combinedObjectsRoot;
|
||
slicerRoot = slicerRootObj.transform;
|
||
Debug.Log($"创建切割结果根节点: {slicerRootObj.name}");
|
||
}
|
||
|
||
// 预先检查要切割的物体是否是Prefab实例,如果是,解除Prefab链接
|
||
foreach (var root in Target.rootsToSlice)
|
||
{
|
||
if (root == null) continue;
|
||
|
||
bool isPrefabInstance = PrefabUtility.IsPartOfPrefabInstance(root.gameObject);
|
||
if (isPrefabInstance && !Target.preserveOriginalModels)
|
||
{
|
||
// 获取Prefab实例的根GameObject
|
||
GameObject prefabRoot = PrefabUtility.GetOutermostPrefabInstanceRoot(root.gameObject);
|
||
|
||
if (prefabRoot != null)
|
||
{
|
||
Debug.Log($"物体 {root.name} 是Prefab实例的一部分,将解除其根节点 {prefabRoot.name} 的Prefab链接");
|
||
PrefabUtility.UnpackPrefabInstance(prefabRoot, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
|
||
}
|
||
else
|
||
{
|
||
Debug.LogWarning($"无法获取物体 {root.name} 的Prefab根节点,跳过解除Prefab链接");
|
||
}
|
||
}
|
||
}
|
||
|
||
// 调用模型切割工具执行切割,根据用户设置决定切割行为
|
||
ModelSlicerUtil.Instance.SliceModels(
|
||
Target.rootsToSlice,
|
||
Target.ground,
|
||
Target.sliceMaterial,
|
||
Target.slicePlaneDirection,
|
||
Target.ignoreObjectBoundsCheck,
|
||
Target.sliceAsynchronously,
|
||
Target.preserveOriginalModels, // 使用用户的设置,决定是否保留原始模型
|
||
slicerRoot, // 当preserveOriginalModels为true时使用SlicerRoot,否则为null(使用原始节点)
|
||
Target.saveMeshesToAssets, // 是否保存网格到Assets
|
||
Target.meshSavePath, // 网格保存路径
|
||
Target.addTimestampToMeshName // 是否添加时间戳
|
||
).Wait(); // 同步等待切割完成
|
||
|
||
var message = Target.preserveOriginalModels ?
|
||
"模型切割处理完成,切割后的上半部分模型已放置在SlicerRoot节点下,原始模型未改变" :
|
||
"模型切割处理完成,切割后的上半部分模型已替换原始模型,原始模型已移除";
|
||
|
||
// 如果保存了网格,添加相关信息
|
||
if (Target.saveMeshesToAssets)
|
||
{
|
||
message += $"\n切割后的网格已保存到路径: Assets/{Target.meshSavePath}";
|
||
}
|
||
|
||
Debug.Log(message);
|
||
|
||
// 标记场景为已修改,以便保存
|
||
EditorUtility.SetDirty(Target.gameObject);
|
||
EditorSceneManager.MarkSceneDirty(Target.gameObject.scene);
|
||
}
|
||
}
|