2024-01-16 14:23:05 +08:00
|
|
|
|
using Sirenix.OdinInspector.Editor;
|
|
|
|
|
|
using UnityEditor;
|
2025-04-07 14:18:07 +08:00
|
|
|
|
using UnityEditor.SceneManagement;
|
2024-01-16 14:23:05 +08:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
[CustomEditor(typeof(PostProcessInstructor))]
|
|
|
|
|
|
public class PostProcessInstructorInspector : OdinEditor
|
|
|
|
|
|
{
|
|
|
|
|
|
private PostProcessInstructor Target => target as PostProcessInstructor;
|
|
|
|
|
|
|
|
|
|
|
|
public override void OnInspectorGUI()
|
|
|
|
|
|
{
|
|
|
|
|
|
base.OnInspectorGUI();
|
2025-04-07 14:18:07 +08:00
|
|
|
|
|
|
|
|
|
|
EditorGUILayout.Space();
|
2025-06-16 17:25:12 +08:00
|
|
|
|
|
|
|
|
|
|
var postProcessInstructors = FindObjectsOfType<PostProcessInstructor>();
|
2025-04-07 14:18:07 +08:00
|
|
|
|
|
|
|
|
|
|
using (new EditorGUILayout.HorizontalScope())
|
2024-01-16 14:23:05 +08:00
|
|
|
|
{
|
2025-04-07 14:18:07 +08:00
|
|
|
|
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);
|
|
|
|
|
|
}
|
2025-06-16 17:25:12 +08:00
|
|
|
|
|
|
|
|
|
|
if (postProcessInstructors.Length > 1 && GUILayout.Button("多节点后处理"))
|
|
|
|
|
|
{
|
|
|
|
|
|
ObjectPostProcessorManager.Instance.PostProcessMore(postProcessInstructors);
|
|
|
|
|
|
}
|
2024-01-16 14:23:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-07 14:18:07 +08:00
|
|
|
|
|
|
|
|
|
|
/// <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);
|
|
|
|
|
|
}
|
2024-01-16 14:23:05 +08:00
|
|
|
|
}
|