Unity 编辑器扩展:3D 空间中绘制安全区棱柱体(含撤销/恢复/保存/读取)
在虚拟现实(VR)和增强现实(AR)开发中,安全区 是保障用户安全的重要组成部分。通过精确控制用户活动范围,可以避免用户与虚拟环境中的物体发生碰撞,确保舒适的体验。在本篇博客中,我们将实现一个 Unity 编辑器插件 ,用来 在 3D 空间中交互式绘制安全区棱柱体,并支持撤销/恢复、保存/读取功能。
功能概述
主要功能:
-
在 XZ 平面中绘制闭合路径:用户通过鼠标点击在 Scene 视图中绘制安全区的边界。
-
设置高度范围:可以定义每个安全区的起始高度和结束高度,生成棱柱体。

-
撤销与恢复:支持撤销上一个绘制点,并恢复已撤销的点。
-
保存与加载:用户可以将绘制的数据保存为 JSON 格式,并从文件中加载。
-
生成 Mesh 与 Collider :通过绘制的点生成对应的 Mesh 和 MeshCollider,作为安全区的碰撞检测区域。
应用场景
- XR 项目开发:在 VR 或 AR 环境中,安全区用于避免用户与虚拟物体发生碰撞或越界。
- 游戏开发:某些游戏场景中需要限制玩家活动区域,例如在竞技场或战斗区域内定义活动边界。
- 室内定位与导航:AR 导航应用中,为了确保用户的安全,通常会设置一个虚拟边界。
编辑器扩展插件实现
本教程将介绍如何使用 Unity 编辑器扩展功能,在 3D 空间中绘制一个安全区的棱柱体,并支持实时显示与编辑。
插件结构与设计
插件的核心功能是基于 EditorWindow
和 SceneView
进行实现。我们将创建一个编辑器窗口,通过点击绘制点生成一个闭合的多边形,并根据用户设定的起始高度和结束高度生成棱柱体。
csharp
public class LineDrawingTool : EditorWindow
{
[MenuItem("Tools/线条绘制工具")]
public static void ShowWindow() { ... }
private void OnGUI() { ... } // 工具窗口 UI
private void OnSceneGUI(SceneView sceneView) { ... } // Scene 绘制
private void GeneratePrismMesh() { ... } // 生成 Mesh
private void SaveData() { ... } // 保存数据
private void LoadData() { ... } // 加载数据
}
编辑器窗口 UI
在 OnGUI
方法中,我们将使用 Unity 的 GUI 系统来构建一个简洁易用的界面。界面包括:
- 开始/结束绘制:用户可以点击按钮开始绘制或结束当前绘制。
- 撤销/恢复:支持撤销上一个点,并恢复已撤销的点。
- 高度设置:输入框允许用户设置安全区的起始高度和结束高度。
- 保存/加载:可以将绘制的数据保存为 JSON 文件,也可以从文件中加载数据。
- 生成 Mesh:用户可以点击按钮生成 Mesh 和 MeshCollider。
以下是 OnGUI
方法的核心实现:
csharp
private void OnGUI()
{
GUILayout.Space(10);
EditorGUILayout.LabelField("安全区棱柱绘制工具", EditorStyles.boldLabel);
// 绘制状态控制
if (GUILayout.Button(isDrawing ? "结束绘制" : "开始绘制", GUILayout.Height(30)))
{
isDrawing = !isDrawing;
SceneView.RepaintAll();
}
// 撤销/恢复功能
EditorGUILayout.BeginHorizontal();
GUI.enabled = points.Count > 0;
if (GUILayout.Button("撤销", GUILayout.Height(25)))
{
// 撤销上一个点
}
GUI.enabled = undoStack.Count > 0;
if (GUILayout.Button("恢复", GUILayout.Height(25)))
{
// 恢复上次撤销的点
}
GUI.enabled = true;
EditorGUILayout.EndHorizontal();
// 高度设置
EditorGUILayout.LabelField("高度范围", EditorStyles.boldLabel);
float newStartHeight = EditorGUILayout.FloatField("起始高度", startHeight);
float newEndHeight = EditorGUILayout.FloatField("结束高度", endHeight);
if (!Mathf.Approximately(newStartHeight, startHeight) || !Mathf.Approximately(newEndHeight, endHeight))
{
startHeight = newStartHeight;
endHeight = newEndHeight;
SceneView.RepaintAll();
}
// 保存与读取
if (GUILayout.Button("保存绘制数据"))
{
SaveData();
}
if (GUILayout.Button("读取绘制数据"))
{
LoadData();
}
}
绘制与生成 Mesh
绘制路径的过程中,我们使用了 SceneView
中的 OnSceneGUI
方法实时监听鼠标输入,并在视图中绘制路径线条和当前点。
在用户设置好高度后,我们将顶面和底面按顶点生成三角形,侧面通过连接相邻的顶点来构建。
csharp
private void GeneratePrismMesh()
{
// 使用顶点生成顶面、底面和侧面
Mesh mesh = new Mesh();
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.RecalculateNormals();
// 创建 GameObject 和 MeshCollider
GameObject prism = new GameObject("SafeZone_Prism");
prism.AddComponent<MeshFilter>().sharedMesh = mesh;
prism.AddComponent<MeshRenderer>().sharedMaterial = ...;
prism.AddComponent<MeshCollider>().sharedMesh = mesh;
}
数据保存与加载
为了持久化绘制的数据,我们将其保存为 JSON 格式。这使得用户可以方便地保存并恢复绘制的安全区。
csharp
private void SaveData()
{
LineDrawingData data = new LineDrawingData { points = points, startHeight = startHeight, endHeight = endHeight };
string json = JsonUtility.ToJson(data, true);
File.WriteAllText(path, json);
}
private void LoadData()
{
string json = File.ReadAllText(path);
LineDrawingData data = JsonUtility.FromJson<LineDrawingData>(json);
points = data.points;
startHeight = data.startHeight;
endHeight = data.endHeight;
SceneView.RepaintAll();
}
可扩展性与优化建议
这个插件提供了一个基础的框架,可以根据具体需求进一步扩展与优化:
- 支持多区域绘制:可以支持多个安全区的绘制与管理。
- 实时网格更新:在编辑过程中实时更新 Mesh 的预览。
- 吸附网格与参考线:为绘制提供网格对齐和参考辅助线。
- 导出为 ScriptableObject:将绘制的安全区作为资源保存,便于复用。
结论
通过本教程,你已经掌握了如何在 Unity 编辑器中创建一个交互式的安全区棱柱体绘制工具,并能够实现撤销、恢复、保存与读取功能。这个插件不仅可以帮助开发者快速创建安全区,还能方便地管理和重用已有的区域设置。
希望这篇博客能帮助你提高开发效率。如果你有其他问题或改进建议,欢迎在评论区留言交流!
源码与示例项目
项目源码可以通过以下链接获取(或留言):源码地址
后续还会分享更多关于 Unity 编辑器工具开发、XR 项目优化等内容,敬请关注!